diff --git a/.github/workflows/build_asan.yml b/.github/workflows/build_asan.yml new file mode 100644 index 00000000..82af7a4e --- /dev/null +++ b/.github/workflows/build_asan.yml @@ -0,0 +1,68 @@ +name: ASAN + +on: + push: + paths: + - "**/workflows/build_asan.yml" + - "**/Source/**" + - "**/Tests/**" + - "**/ThirdParty/**" + - "**/CMakeLists.txt" + - "**/.gitmodules" + - "!**/*.md" + - "!**/*.txt" + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + BUILD_TYPE: RelWithDebInfo + +jobs: + lua: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + lua: + - { version: "5.1", suffix: "51" } + - { version: "5.2", suffix: "52" } + - { version: "5.3", suffix: "53" } + - { version: "5.4", suffix: "54" } + - { version: "5.5", suffix: "55" } + + steps: + + - uses: actions/checkout@v6 + with: + submodules: true + + - name: Install Dependencies + run: sudo apt-get -y install ninja-build + + - name: Create Build Environment + run: cmake -E make_directory ${{runner.workspace}}/build + + - name: Configure + working-directory: ${{runner.workspace}}/build + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DLUABRIDGE_SANITIZE=address -G Ninja + + - name: Build Lua ${{ matrix.lua.version }} + working-directory: ${{runner.workspace}}/build + run: | + cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \ + LuaBridgeTests${{ matrix.lua.suffix }} \ + LuaBridgeTests${{ matrix.lua.suffix }}LuaC \ + LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \ + LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept + + - name: Test Lua ${{ matrix.lua.version }} + working-directory: ${{runner.workspace}}/build/Tests + env: + ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0 + run: | + ./LuaBridgeTests${{ matrix.lua.suffix }} + ./LuaBridgeTests${{ matrix.lua.suffix }}LuaC + ./LuaBridgeTests${{ matrix.lua.suffix }}Noexcept + ./LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index f916a7c3..06430c9c 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -1,4 +1,4 @@ -name: Build Linux +name: Linux on: push: @@ -20,148 +20,18 @@ env: BUILD_TYPE: Release jobs: - lua51: + lua: runs-on: ubuntu-latest - steps: - - - uses: actions/checkout@v6 - with: - submodules: true - - - name: Install Dependencies - run: sudo apt-get -y install ninja-build - - - name: Create Build Environment - run: cmake -E make_directory ${{runner.workspace}}/build - - - name: Configure - working-directory: ${{runner.workspace}}/build - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja - - - name: Build Lua 5.1 - working-directory: ${{runner.workspace}}/build - run: | - cmake --build . --config $BUILD_TYPE --parallel 4 --target \ - LuaBridgeTests51 \ - LuaBridgeTests51LuaC \ - LuaBridgeTests51Noexcept \ - LuaBridgeTests51LuaCNoexcept - - - name: Test Lua 5.1 - working-directory: ${{runner.workspace}}/build/Tests - run: | - ./LuaBridgeTests51 - ./LuaBridgeTests51LuaC - ./LuaBridgeTests51Noexcept - ./LuaBridgeTests51LuaCNoexcept - - lua52: - runs-on: ubuntu-latest - steps: - - - uses: actions/checkout@v6 - with: - submodules: true - - - name: Install Dependencies - run: sudo apt-get -y install ninja-build - - - name: Create Build Environment - run: cmake -E make_directory ${{runner.workspace}}/build + strategy: + fail-fast: false + matrix: + lua: + - { version: "5.1", suffix: "51" } + - { version: "5.2", suffix: "52" } + - { version: "5.3", suffix: "53" } + - { version: "5.4", suffix: "54" } + - { version: "5.5", suffix: "55" } - - name: Configure - working-directory: ${{runner.workspace}}/build - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja - - - name: Build Lua 5.2 - working-directory: ${{runner.workspace}}/build - run: | - cmake --build . --config $BUILD_TYPE --parallel 4 --target \ - LuaBridgeTests52 \ - LuaBridgeTests52LuaC \ - LuaBridgeTests52Noexcept \ - LuaBridgeTests52LuaCNoexcept - - - name: Test Lua 5.2 - working-directory: ${{runner.workspace}}/build/Tests - run: | - ./LuaBridgeTests52 - ./LuaBridgeTests52LuaC - ./LuaBridgeTests52Noexcept - ./LuaBridgeTests52LuaCNoexcept - - lua53: - runs-on: ubuntu-latest - steps: - - - uses: actions/checkout@v6 - with: - submodules: true - - - name: Install Dependencies - run: sudo apt-get -y install ninja-build - - - name: Create Build Environment - run: cmake -E make_directory ${{runner.workspace}}/build - - - name: Configure - working-directory: ${{runner.workspace}}/build - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja - - - name: Build Lua 5.3 - working-directory: ${{runner.workspace}}/build - run: | - cmake --build . --config $BUILD_TYPE --parallel 4 --target \ - LuaBridgeTests53 \ - LuaBridgeTests53LuaC \ - LuaBridgeTests53Noexcept \ - LuaBridgeTests53LuaCNoexcept - - - name: Test Lua 5.3 - working-directory: ${{runner.workspace}}/build/Tests - run: | - ./LuaBridgeTests53 - ./LuaBridgeTests53LuaC - ./LuaBridgeTests53Noexcept - ./LuaBridgeTests53LuaCNoexcept - - lua54: - runs-on: ubuntu-latest - steps: - - - uses: actions/checkout@v6 - with: - submodules: true - - - name: Install Dependencies - run: sudo apt-get -y install ninja-build - - - name: Create Build Environment - run: cmake -E make_directory ${{runner.workspace}}/build - - - name: Configure - working-directory: ${{runner.workspace}}/build - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja - - - name: Build Lua 5.4 - working-directory: ${{runner.workspace}}/build - run: | - cmake --build . --config $BUILD_TYPE --parallel 4 --target \ - LuaBridgeTests54 \ - LuaBridgeTests54LuaC \ - LuaBridgeTests54Noexcept \ - LuaBridgeTests54LuaCNoexcept - - - name: Test Lua 5.4 - working-directory: ${{runner.workspace}}/build/Tests - run: | - ./LuaBridgeTests54 - ./LuaBridgeTests54LuaC - ./LuaBridgeTests54Noexcept - ./LuaBridgeTests54LuaCNoexcept - - lua55: - runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 @@ -178,22 +48,22 @@ jobs: working-directory: ${{runner.workspace}}/build run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja - - name: Build Lua 5.5 + - name: Build Lua ${{ matrix.lua.version }} working-directory: ${{runner.workspace}}/build run: | - cmake --build . --config $BUILD_TYPE --parallel 4 --target \ - LuaBridgeTests55 \ - LuaBridgeTests55LuaC \ - LuaBridgeTests55Noexcept \ - LuaBridgeTests55LuaCNoexcept + cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \ + LuaBridgeTests${{ matrix.lua.suffix }} \ + LuaBridgeTests${{ matrix.lua.suffix }}LuaC \ + LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \ + LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept - - name: Test Lua 5.5 + - name: Test Lua ${{ matrix.lua.version }} working-directory: ${{runner.workspace}}/build/Tests run: | - ./LuaBridgeTests55 - ./LuaBridgeTests55LuaC - ./LuaBridgeTests55Noexcept - ./LuaBridgeTests55LuaCNoexcept + ./LuaBridgeTests${{ matrix.lua.suffix }} + ./LuaBridgeTests${{ matrix.lua.suffix }}LuaC + ./LuaBridgeTests${{ matrix.lua.suffix }}Noexcept + ./LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept luajit: runs-on: ubuntu-latest @@ -218,7 +88,7 @@ jobs: - name: Build LuaJIT working-directory: ${{runner.workspace}}/build run: | - cmake --build . --config $BUILD_TYPE --parallel 4 --target \ + cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \ LuaBridgeTestsLuaJIT \ LuaBridgeTestsLuaJITNoexcept @@ -248,7 +118,7 @@ jobs: - name: Build Luau working-directory: ${{runner.workspace}}/build - run: cmake --build . --config $BUILD_TYPE --parallel 4 --target LuaBridgeTestsLuau + run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsLuau - name: Test Luau working-directory: ${{runner.workspace}}/build/Tests @@ -274,7 +144,7 @@ jobs: - name: Build Ravi working-directory: ${{runner.workspace}}/build - run: cmake --build . --config $BUILD_TYPE --parallel 4 --target LuaBridgeTestsRavi + run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsRavi - name: Test Ravi working-directory: ${{runner.workspace}}/build/Tests diff --git a/.github/workflows/build_macos.yml b/.github/workflows/build_macos.yml index 172a1854..0ff61011 100644 --- a/.github/workflows/build_macos.yml +++ b/.github/workflows/build_macos.yml @@ -1,4 +1,4 @@ -name: Build MacOS +name: macOS on: push: @@ -20,136 +20,18 @@ env: BUILD_TYPE: Release jobs: - lua51: + lua: runs-on: macos-latest - steps: - - - uses: actions/checkout@v6 - with: - submodules: true - - - name: Create Build Environment - run: cmake -E make_directory ${{runner.workspace}}/build - - - name: Configure - working-directory: ${{runner.workspace}}/build - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja - - - name: Build Lua 5.1 - working-directory: ${{runner.workspace}}/build - run: | - cmake --build . --config $BUILD_TYPE --parallel 4 --target \ - LuaBridgeTests51 \ - LuaBridgeTests51LuaC \ - LuaBridgeTests51Noexcept \ - LuaBridgeTests51LuaCNoexcept - - - name: Test Lua 5.1 - working-directory: ${{runner.workspace}}/build/Tests - run: | - ./LuaBridgeTests51 - ./LuaBridgeTests51LuaC - ./LuaBridgeTests51Noexcept - ./LuaBridgeTests51LuaCNoexcept - - lua52: - runs-on: macos-latest - steps: - - - uses: actions/checkout@v6 - with: - submodules: true - - - name: Create Build Environment - run: cmake -E make_directory ${{runner.workspace}}/build - - - name: Configure - working-directory: ${{runner.workspace}}/build - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja - - - name: Build Lua 5.2 - working-directory: ${{runner.workspace}}/build - run: | - cmake --build . --config $BUILD_TYPE --parallel 4 --target \ - LuaBridgeTests52 \ - LuaBridgeTests52LuaC \ - LuaBridgeTests52Noexcept \ - LuaBridgeTests52LuaCNoexcept - - - name: Test Lua 5.2 - working-directory: ${{runner.workspace}}/build/Tests - run: | - ./LuaBridgeTests52 - ./LuaBridgeTests52LuaC - ./LuaBridgeTests52Noexcept - ./LuaBridgeTests52LuaCNoexcept - - lua53: - runs-on: macos-latest - steps: - - - uses: actions/checkout@v6 - with: - submodules: true - - - name: Create Build Environment - run: cmake -E make_directory ${{runner.workspace}}/build - - - name: Configure - working-directory: ${{runner.workspace}}/build - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja - - - name: Build Lua 5.3 - working-directory: ${{runner.workspace}}/build - run: | - cmake --build . --config $BUILD_TYPE --parallel 4 --target \ - LuaBridgeTests53 \ - LuaBridgeTests53LuaC \ - LuaBridgeTests53Noexcept \ - LuaBridgeTests53LuaCNoexcept - - - name: Test Lua 5.3 - working-directory: ${{runner.workspace}}/build/Tests - run: | - ./LuaBridgeTests53 - ./LuaBridgeTests53LuaC - ./LuaBridgeTests53Noexcept - ./LuaBridgeTests53LuaCNoexcept - - lua54: - runs-on: macos-latest - steps: - - - uses: actions/checkout@v6 - with: - submodules: true - - - name: Create Build Environment - run: cmake -E make_directory ${{runner.workspace}}/build - - - name: Configure - working-directory: ${{runner.workspace}}/build - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja - - - name: Build Lua 5.4 - working-directory: ${{runner.workspace}}/build - run: | - cmake --build . --config $BUILD_TYPE --parallel 4 --target \ - LuaBridgeTests54 \ - LuaBridgeTests54LuaC \ - LuaBridgeTests54Noexcept \ - LuaBridgeTests54LuaCNoexcept + strategy: + fail-fast: false + matrix: + lua: + - { version: "5.1", suffix: "51" } + - { version: "5.2", suffix: "52" } + - { version: "5.3", suffix: "53" } + - { version: "5.4", suffix: "54" } + - { version: "5.5", suffix: "55" } - - name: Test Lua 5.4 - working-directory: ${{runner.workspace}}/build/Tests - run: | - ./LuaBridgeTests54 - ./LuaBridgeTests54LuaC - ./LuaBridgeTests54Noexcept - ./LuaBridgeTests54LuaCNoexcept - - lua55: - runs-on: macos-latest steps: - uses: actions/checkout@v6 @@ -163,22 +45,22 @@ jobs: working-directory: ${{runner.workspace}}/build run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja - - name: Build Lua 5.5 + - name: Build Lua ${{ matrix.lua.version }} working-directory: ${{runner.workspace}}/build run: | - cmake --build . --config $BUILD_TYPE --parallel 4 --target \ - LuaBridgeTests55 \ - LuaBridgeTests55LuaC \ - LuaBridgeTests55Noexcept \ - LuaBridgeTests55LuaCNoexcept + cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \ + LuaBridgeTests${{ matrix.lua.suffix }} \ + LuaBridgeTests${{ matrix.lua.suffix }}LuaC \ + LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \ + LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept - - name: Test Lua 5.5 + - name: Test Lua ${{ matrix.lua.version }} working-directory: ${{runner.workspace}}/build/Tests run: | - ./LuaBridgeTests55 - ./LuaBridgeTests55LuaC - ./LuaBridgeTests55Noexcept - ./LuaBridgeTests55LuaCNoexcept + ./LuaBridgeTests${{ matrix.lua.suffix }} + ./LuaBridgeTests${{ matrix.lua.suffix }}LuaC + ./LuaBridgeTests${{ matrix.lua.suffix }}Noexcept + ./LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept luajit: runs-on: macos-latest @@ -198,7 +80,7 @@ jobs: - name: Build LuaJIT working-directory: ${{runner.workspace}}/build run: | - cmake --build . --config $BUILD_TYPE --parallel 4 --target \ + cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \ LuaBridgeTestsLuaJIT \ LuaBridgeTestsLuaJITNoexcept @@ -225,7 +107,7 @@ jobs: - name: Build Luau working-directory: ${{runner.workspace}}/build - run: cmake --build . --config $BUILD_TYPE --parallel 4 --target LuaBridgeTestsLuau + run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsLuau - name: Test Luau working-directory: ${{runner.workspace}}/build/Tests @@ -246,9 +128,9 @@ jobs: working-directory: ${{runner.workspace}}/build run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja - - name: Build LuaJIT + - name: Build Ravi working-directory: ${{runner.workspace}}/build - run: cmake --build . --config $BUILD_TYPE --parallel 4 --target LuaBridgeTestsRavi + run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsRavi - name: Test Ravi working-directory: ${{runner.workspace}}/build/Tests diff --git a/.github/workflows/build_tsan.yml_ b/.github/workflows/build_tsan.yml_ new file mode 100644 index 00000000..f0dbed88 --- /dev/null +++ b/.github/workflows/build_tsan.yml_ @@ -0,0 +1,68 @@ +name: TSAN + +on: + push: + paths: + - "**/workflows/build_tsan.yml" + - "**/Source/**" + - "**/Tests/**" + - "**/ThirdParty/**" + - "**/CMakeLists.txt" + - "**/.gitmodules" + - "!**/*.md" + - "!**/*.txt" + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + BUILD_TYPE: RelWithDebInfo + +jobs: + lua: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + lua: + - { version: "5.1", suffix: "51" } + - { version: "5.2", suffix: "52" } + - { version: "5.3", suffix: "53" } + - { version: "5.4", suffix: "54" } + - { version: "5.5", suffix: "55" } + + steps: + + - uses: actions/checkout@v6 + with: + submodules: true + + - name: Install Dependencies + run: sudo apt-get -y install ninja-build + + - name: Create Build Environment + run: cmake -E make_directory ${{runner.workspace}}/build + + - name: Configure + working-directory: ${{runner.workspace}}/build + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DLUABRIDGE_SANITIZE=thread -G Ninja + + - name: Build Lua ${{ matrix.lua.version }} + working-directory: ${{runner.workspace}}/build + run: | + cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \ + LuaBridgeTests${{ matrix.lua.suffix }} \ + LuaBridgeTests${{ matrix.lua.suffix }}LuaC \ + LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \ + LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept + + - name: Test Lua ${{ matrix.lua.version }} + working-directory: ${{runner.workspace}}/build/Tests + env: + TSAN_OPTIONS: halt_on_error=1:print_stacktrace=1 + run: | + ./LuaBridgeTests${{ matrix.lua.suffix }} + ./LuaBridgeTests${{ matrix.lua.suffix }}LuaC + ./LuaBridgeTests${{ matrix.lua.suffix }}Noexcept + ./LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept diff --git a/.github/workflows/build_ubsan.yml b/.github/workflows/build_ubsan.yml new file mode 100644 index 00000000..88691cf4 --- /dev/null +++ b/.github/workflows/build_ubsan.yml @@ -0,0 +1,68 @@ +name: UBSAN + +on: + push: + paths: + - "**/workflows/build_ubsan.yml" + - "**/Source/**" + - "**/Tests/**" + - "**/ThirdParty/**" + - "**/CMakeLists.txt" + - "**/.gitmodules" + - "!**/*.md" + - "!**/*.txt" + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + BUILD_TYPE: RelWithDebInfo + +jobs: + lua: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + lua: + - { version: "5.1", suffix: "51" } + - { version: "5.2", suffix: "52" } + - { version: "5.3", suffix: "53" } + - { version: "5.4", suffix: "54" } + - { version: "5.5", suffix: "55" } + + steps: + + - uses: actions/checkout@v6 + with: + submodules: true + + - name: Install Dependencies + run: sudo apt-get -y install ninja-build + + - name: Create Build Environment + run: cmake -E make_directory ${{runner.workspace}}/build + + - name: Configure + working-directory: ${{runner.workspace}}/build + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DLUABRIDGE_SANITIZE=undefined -G Ninja + + - name: Build Lua ${{ matrix.lua.version }} + working-directory: ${{runner.workspace}}/build + run: | + cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \ + LuaBridgeTests${{ matrix.lua.suffix }} \ + LuaBridgeTests${{ matrix.lua.suffix }}LuaC \ + LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \ + LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept + + - name: Test Lua ${{ matrix.lua.version }} + working-directory: ${{runner.workspace}}/build/Tests + env: + UBSAN_OPTIONS: halt_on_error=1:print_stacktrace=1 + run: | + ./LuaBridgeTests${{ matrix.lua.suffix }} + ./LuaBridgeTests${{ matrix.lua.suffix }}LuaC + ./LuaBridgeTests${{ matrix.lua.suffix }}Noexcept + ./LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml index edfb867a..a67bb15b 100644 --- a/.github/workflows/build_windows.yml +++ b/.github/workflows/build_windows.yml @@ -1,4 +1,4 @@ -name: Build Windows +name: Windows on: push: @@ -20,148 +20,18 @@ env: BUILD_TYPE: Release jobs: - lua51: + lua: runs-on: windows-latest - steps: - - - uses: actions/checkout@v6 - with: - submodules: true - - - name: Create Build Environment - run: cmake -E make_directory ${{runner.workspace}}/build - - - name: Configure - shell: bash - working-directory: ${{runner.workspace}}/build - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE - - - name: Build Lua 5.1 - working-directory: ${{runner.workspace}}/build - shell: bash - run: | - cmake --build . --config $BUILD_TYPE --parallel 4 --target \ - LuaBridgeTests51 \ - LuaBridgeTests51LuaC \ - LuaBridgeTests51Noexcept \ - LuaBridgeTests51LuaCNoexcept - - - name: Test Lua 5.1 - working-directory: ${{runner.workspace}}/build/Tests/Release - shell: bash - run: | - ./LuaBridgeTests51.exe - ./LuaBridgeTests51LuaC.exe - ./LuaBridgeTests51Noexcept.exe - ./LuaBridgeTests51LuaCNoexcept.exe - - lua52: - runs-on: windows-latest - steps: - - - uses: actions/checkout@v6 - with: - submodules: true - - - name: Create Build Environment - run: cmake -E make_directory ${{runner.workspace}}/build - - - name: Configure - shell: bash - working-directory: ${{runner.workspace}}/build - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE - - - name: Build Lua 5.2 - working-directory: ${{runner.workspace}}/build - shell: bash - run: | - cmake --build . --config $BUILD_TYPE --parallel 4 --target \ - LuaBridgeTests52 \ - LuaBridgeTests52LuaC \ - LuaBridgeTests52Noexcept \ - LuaBridgeTests52LuaCNoexcept + strategy: + fail-fast: false + matrix: + lua: + - { version: "5.1", suffix: "51" } + - { version: "5.2", suffix: "52" } + - { version: "5.3", suffix: "53" } + - { version: "5.4", suffix: "54" } + - { version: "5.5", suffix: "55" } - - name: Test Lua 5.2 - working-directory: ${{runner.workspace}}/build/Tests/Release - shell: bash - run: | - ./LuaBridgeTests52.exe - ./LuaBridgeTests52LuaC.exe - ./LuaBridgeTests52Noexcept.exe - ./LuaBridgeTests52LuaCNoexcept.exe - - lua53: - runs-on: windows-latest - steps: - - - uses: actions/checkout@v6 - with: - submodules: true - - - name: Create Build Environment - run: cmake -E make_directory ${{runner.workspace}}/build - - - name: Configure - shell: bash - working-directory: ${{runner.workspace}}/build - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE - - - name: Build Lua 5.3 - working-directory: ${{runner.workspace}}/build - shell: bash - run: | - cmake --build . --config $BUILD_TYPE --parallel 4 --target \ - LuaBridgeTests53 \ - LuaBridgeTests53LuaC \ - LuaBridgeTests53Noexcept \ - LuaBridgeTests53LuaCNoexcept - - - name: Test Lua 5.3 - working-directory: ${{runner.workspace}}/build/Tests/Release - shell: bash - run: | - ./LuaBridgeTests53.exe - ./LuaBridgeTests53LuaC.exe - ./LuaBridgeTests53Noexcept.exe - ./LuaBridgeTests53LuaCNoexcept.exe - - lua54: - runs-on: windows-latest - steps: - - - uses: actions/checkout@v6 - with: - submodules: true - - - name: Create Build Environment - run: cmake -E make_directory ${{runner.workspace}}/build - - - name: Configure - shell: bash - working-directory: ${{runner.workspace}}/build - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE - - - name: Build Lua 5.4 - working-directory: ${{runner.workspace}}/build - shell: bash - run: | - cmake --build . --config $BUILD_TYPE --parallel 4 --target \ - LuaBridgeTests54 \ - LuaBridgeTests54LuaC \ - LuaBridgeTests54Noexcept \ - LuaBridgeTests54LuaCNoexcept - - - name: Test Lua 5.4 - working-directory: ${{runner.workspace}}/build/Tests/Release - shell: bash - run: | - ./LuaBridgeTests54.exe - ./LuaBridgeTests54LuaC.exe - ./LuaBridgeTests54Noexcept.exe - ./LuaBridgeTests54LuaCNoexcept.exe - - lua55: - runs-on: windows-latest steps: - uses: actions/checkout@v6 @@ -176,24 +46,24 @@ jobs: working-directory: ${{runner.workspace}}/build run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE - - name: Build Lua 5.5 + - name: Build Lua ${{ matrix.lua.version }} working-directory: ${{runner.workspace}}/build shell: bash run: | cmake --build . --config $BUILD_TYPE --parallel 4 --target \ - LuaBridgeTests55 \ - LuaBridgeTests55LuaC \ - LuaBridgeTests55Noexcept \ - LuaBridgeTests55LuaCNoexcept + LuaBridgeTests${{ matrix.lua.suffix }} \ + LuaBridgeTests${{ matrix.lua.suffix }}LuaC \ + LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \ + LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept - - name: Test Lua 5.5 + - name: Test Lua ${{ matrix.lua.version }} working-directory: ${{runner.workspace}}/build/Tests/Release shell: bash run: | - ./LuaBridgeTests55.exe - ./LuaBridgeTests55LuaC.exe - ./LuaBridgeTests55Noexcept.exe - ./LuaBridgeTests55LuaCNoexcept.exe + ./LuaBridgeTests${{ matrix.lua.suffix }}.exe + ./LuaBridgeTests${{ matrix.lua.suffix }}LuaC.exe + ./LuaBridgeTests${{ matrix.lua.suffix }}Noexcept.exe + ./LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept.exe luajit: runs-on: windows-latest diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index ee811877..e79992d9 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,4 +1,4 @@ -name: "CodeQL" +name: CodeQL on: push: @@ -59,7 +59,7 @@ jobs: - name: Build working-directory: ${{runner.workspace}}/build shell: bash - run: cmake --build . --config $BUILD_TYPE + run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index e7c7e3e6..a558dfd9 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -1,4 +1,4 @@ -name: Code Coverage +name: Coverage on: push: @@ -20,59 +20,18 @@ env: BUILD_TYPE: Debug jobs: - lua51: + lua: runs-on: ubuntu-latest - steps: - - - uses: actions/checkout@v6 - with: - submodules: true + strategy: + fail-fast: false + matrix: + lua: + - { version: "5.1", suffix: "51" } + - { version: "5.2", suffix: "52" } + - { version: "5.3", suffix: "53" } + - { version: "5.4", suffix: "54" } + - { version: "5.5", suffix: "55" } - - name: Install lcov - run: sudo apt-get install -y lcov ninja-build - - - name: Create Build Environment - run: | - cmake -E make_directory ${{runner.workspace}}/build - cmake -E make_directory ${{runner.workspace}}/build/coverage - - - name: Configure - working-directory: ${{runner.workspace}}/build - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DLUABRIDGE_COVERAGE=ON -G Ninja - - - name: Build Lua 5.1 - working-directory: ${{runner.workspace}}/build - run: | - cmake --build . --config $BUILD_TYPE --parallel 4 --target \ - LuaBridgeTests51 \ - LuaBridgeTests51LuaC \ - LuaBridgeTests51Noexcept \ - LuaBridgeTests51LuaCNoexcept - - - name: Test Lua 5.1 - working-directory: ${{runner.workspace}}/build/Tests - run: | - ./LuaBridgeTests51 - ./LuaBridgeTests51LuaC - ./LuaBridgeTests51Noexcept - ./LuaBridgeTests51LuaCNoexcept - - - name: Coverage Lua 5.1 - working-directory: ${{runner.workspace}}/build - run: | - lcov -c -d "${{runner.workspace}}/build" --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 \ - --ignore-errors mismatch,unused \ - --include "*/LuaBridge/*" --exclude "*/Tests/*" --exclude "*/Distribution/*" --exclude "*/coverage_html/*" \ - -o "coverage/lua51.info" - - - name: Cache Lcov Files - uses: actions/cache@v5 - with: - path: "${{runner.workspace}}/build/coverage/*.info" - key: lcov-lua51-${{runner.os}}-${{github.sha}} - - lua52: - runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 @@ -91,189 +50,36 @@ jobs: working-directory: ${{runner.workspace}}/build run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DLUABRIDGE_COVERAGE=ON -G Ninja - - name: Build Lua 5.2 + - name: Build Lua ${{ matrix.lua.version }} working-directory: ${{runner.workspace}}/build run: | - cmake --build . --config $BUILD_TYPE --parallel 4 --target \ - LuaBridgeTests52 \ - LuaBridgeTests52LuaC \ - LuaBridgeTests52Noexcept \ - LuaBridgeTests52LuaCNoexcept + cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \ + LuaBridgeTests${{ matrix.lua.suffix }} \ + LuaBridgeTests${{ matrix.lua.suffix }}LuaC \ + LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \ + LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept - - name: Test Lua 5.2 + - name: Test Lua ${{ matrix.lua.version }} working-directory: ${{runner.workspace}}/build/Tests run: | - ./LuaBridgeTests52 - ./LuaBridgeTests52LuaC - ./LuaBridgeTests52Noexcept - ./LuaBridgeTests52LuaCNoexcept + ./LuaBridgeTests${{ matrix.lua.suffix }} + ./LuaBridgeTests${{ matrix.lua.suffix }}LuaC + ./LuaBridgeTests${{ matrix.lua.suffix }}Noexcept + ./LuaBridgeTests${{ matrix.lua.suffix }}LuaCNoexcept - - name: Coverage Lua 5.2 + - name: Coverage Lua ${{ matrix.lua.version }} working-directory: ${{runner.workspace}}/build run: | lcov -c -d "${{runner.workspace}}/build" --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 \ --ignore-errors mismatch,unused \ --include "*/LuaBridge/*" --exclude "*/Tests/*" --exclude "*/Distribution/*" --exclude "*/coverage_html/*" \ - -o "coverage/lua52.info" + -o "coverage/lua${{ matrix.lua.suffix }}.info" - name: Cache Lcov Files uses: actions/cache@v5 with: path: "${{runner.workspace}}/build/coverage/*.info" - key: lcov-lua52-${{runner.os}}-${{github.sha}} - - lua53: - runs-on: ubuntu-latest - steps: - - - uses: actions/checkout@v6 - with: - submodules: true - - - name: Install lcov - run: sudo apt-get install -y lcov ninja-build - - - name: Create Build Environment - run: | - cmake -E make_directory ${{runner.workspace}}/build - cmake -E make_directory ${{runner.workspace}}/build/coverage - - - name: Configure - working-directory: ${{runner.workspace}}/build - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DLUABRIDGE_COVERAGE=ON -G Ninja - - - name: Build Lua 5.3 - working-directory: ${{runner.workspace}}/build - run: | - cmake --build . --config $BUILD_TYPE --parallel 4 --target \ - LuaBridgeTests53 \ - LuaBridgeTests53LuaC \ - LuaBridgeTests53Noexcept \ - LuaBridgeTests53LuaCNoexcept - - - name: Test Lua 5.3 - working-directory: ${{runner.workspace}}/build/Tests - run: | - ./LuaBridgeTests53 - ./LuaBridgeTests53LuaC - ./LuaBridgeTests53Noexcept - ./LuaBridgeTests53LuaCNoexcept - - - name: Coverage Lua 5.3 - working-directory: ${{runner.workspace}}/build - run: | - lcov -c -d "${{runner.workspace}}/build" --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 \ - --ignore-errors mismatch,unused \ - --include "*/LuaBridge/*" --exclude "*/Tests/*" --exclude "*/Distribution/*" --exclude "*/coverage_html/*" \ - -o "coverage/lua53.info" - - - name: Cache Lcov Files - uses: actions/cache@v5 - with: - path: "${{runner.workspace}}/build/coverage/*.info" - key: lcov-lua53-${{runner.os}}-${{github.sha}} - - lua54: - runs-on: ubuntu-latest - steps: - - - uses: actions/checkout@v6 - with: - submodules: true - - - name: Install lcov - run: sudo apt-get install -y lcov ninja-build - - - name: Create Build Environment - run: | - cmake -E make_directory ${{runner.workspace}}/build - cmake -E make_directory ${{runner.workspace}}/build/coverage - - - name: Configure - working-directory: ${{runner.workspace}}/build - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DLUABRIDGE_COVERAGE=ON -G Ninja - - - name: Build Lua 5.4 - working-directory: ${{runner.workspace}}/build - run: | - cmake --build . --config $BUILD_TYPE --parallel 4 --target \ - LuaBridgeTests54 \ - LuaBridgeTests54LuaC \ - LuaBridgeTests54Noexcept \ - LuaBridgeTests54LuaCNoexcept - - - name: Test Lua 5.4 - working-directory: ${{runner.workspace}}/build/Tests - run: | - ./LuaBridgeTests54 - ./LuaBridgeTests54LuaC - ./LuaBridgeTests54Noexcept - ./LuaBridgeTests54LuaCNoexcept - - - name: Coverage Lua 5.4 - working-directory: ${{runner.workspace}}/build - run: | - lcov -c -d "${{runner.workspace}}/build" --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 \ - --ignore-errors mismatch,unused \ - --include "*/LuaBridge/*" --exclude "*/Tests/*" --exclude "*/Distribution/*" --exclude "*/coverage_html/*" \ - -o "coverage/lua54.info" - - - name: Cache Lcov Files - uses: actions/cache@v5 - with: - path: "${{runner.workspace}}/build/coverage/*.info" - key: lcov-lua54-${{runner.os}}-${{github.sha}} - - lua55: - runs-on: ubuntu-latest - steps: - - - uses: actions/checkout@v6 - with: - submodules: true - - - name: Install lcov - run: sudo apt-get install -y lcov ninja-build - - - name: Create Build Environment - run: | - cmake -E make_directory ${{runner.workspace}}/build - cmake -E make_directory ${{runner.workspace}}/build/coverage - - - name: Configure - working-directory: ${{runner.workspace}}/build - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DLUABRIDGE_COVERAGE=ON -G Ninja - - - name: Build Lua 5.5 - working-directory: ${{runner.workspace}}/build - run: | - cmake --build . --config $BUILD_TYPE --parallel 4 --target \ - LuaBridgeTests55 \ - LuaBridgeTests55LuaC \ - LuaBridgeTests55Noexcept \ - LuaBridgeTests55LuaCNoexcept - - - name: Test Lua 5.5 - working-directory: ${{runner.workspace}}/build/Tests - run: | - ./LuaBridgeTests55 - ./LuaBridgeTests55LuaC - ./LuaBridgeTests55Noexcept - ./LuaBridgeTests55LuaCNoexcept - - - name: Coverage Lua 5.5 - working-directory: ${{runner.workspace}}/build - run: | - lcov -c -d "${{runner.workspace}}/build" --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 \ - --ignore-errors mismatch,unused \ - --include "*/LuaBridge/*" --exclude "*/Tests/*" --exclude "*/Distribution/*" --exclude "*/coverage_html/*" \ - -o "coverage/lua55.info" - - - name: Cache Lcov Files - uses: actions/cache@v5 - with: - path: "${{runner.workspace}}/build/coverage/*.info" - key: lcov-lua55-${{runner.os}}-${{github.sha}} + key: lcov-lua${{ matrix.lua.suffix }}-${{runner.os}}-${{github.sha}} luajit: runs-on: ubuntu-latest @@ -298,7 +104,7 @@ jobs: - name: Build LuaJIT working-directory: ${{runner.workspace}}/build run: | - cmake --build . --config $BUILD_TYPE --parallel 4 --target \ + cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \ LuaBridgeTestsLuaJIT \ LuaBridgeTestsLuaJITNoexcept @@ -344,7 +150,7 @@ jobs: - name: Build Luau working-directory: ${{runner.workspace}}/build - run: cmake --build . --config $BUILD_TYPE --parallel 4 --target LuaBridgeTestsLuau + run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsLuau - name: Test Luau working-directory: ${{runner.workspace}}/build/Tests @@ -386,7 +192,7 @@ jobs: - name: Build Ravi working-directory: ${{runner.workspace}}/build - run: cmake --build . --config $BUILD_TYPE --parallel 4 --target LuaBridgeTestsRavi + run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsRavi - name: Test Ravi working-directory: ${{runner.workspace}}/build/Tests @@ -408,7 +214,7 @@ jobs: coveralls: runs-on: ubuntu-latest - needs: [lua51, lua52, lua53, lua54, lua55, luajit, luau, ravi] + needs: [lua, luajit, luau, ravi] steps: - uses: actions/checkout@v6 with: @@ -491,12 +297,22 @@ jobs: working-directory: ${{runner.workspace}}/build run: lcov2xml coverage/merged.info -o coverage/cobertura.xml + #- name: Convert to Coverage TXT + # working-directory: ${{runner.workspace}}/build + # run: python3 ${{runner.workspace}}/cobertura.py coverage/cobertura.info coverage/coverage.txt + - name: Upload Cobertura XML uses: actions/upload-artifact@v4 with: name: cobertura-coverage path: ${{runner.workspace}}/build/coverage/cobertura.xml + #- name: Upload Coverage TXT + # uses: actions/upload-artifact@v4 + # with: + # name: text-coverage + # path: ${{runner.workspace}}/build/coverage/coverage.txt + - name: Coveralls uses: coverallsapp/github-action@master with: diff --git a/.github/workflows/sonar.yml_ b/.github/workflows/sonar.yml_ index 430cf2f0..cc4e7d6b 100644 --- a/.github/workflows/sonar.yml_ +++ b/.github/workflows/sonar.yml_ @@ -1,4 +1,4 @@ -name: SonarCloud +name: Sonar on: push: diff --git a/CHANGES.md b/CHANGES.md index a47cd16f..a992da8b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -16,23 +16,36 @@ * Breaking Change: Removed `Class::addStaticCFunction`, it was just an alias for `Class::addStaticFunction`. * Allow specifying a non virtual base class method when declaring class members (functions or variables) not exposed in the inherited class. * Allow using capturing lambdas in `Namespace::addFunction`, `Namespace::addProperty`, `Class::addFunction`, `Class::addStaticFunction`, `Class::addProperty` and `Class::addStaticProperty`. -* Added support for specifying factory functor in `Class::addConstructor` to do placement new of the object instance. +* Added multiple inheritance support: `deriveClass` now accepts more than one registered base class (e.g. `deriveClass`). * Added `Namespace::addVariable` to allow adding a modifiable value by copy into the namespace without incurring in function calls or metatables generation. -* Added `getNamespaceFromStack` function to construct a namespace object from a table on the stack. -* Added `registerMainThread` function especially useful when using lua 5.1 to register the main lua thread. +* Added `luabridge::callWithHandler` free function and `LuaRef::callWithHandler` member to provide a custom Lua message handler during `lua_pcall`. +* Added `luabridge::newFunction` free function and `LuaRef::newFunction` static method to wrap any C++ callable into a Lua function exposed as a `LuaRef`. +* Added `luabridge::getNamespaceFromStack` function to construct a namespace object from a table on the stack. +* Added `luabridge::registerMainThread` function especially useful when using lua 5.1 to register the main lua thread. * Added `std::shared_ptr` support for types intrusively deriving from `std::enable_shared_from_this`. +* Added `Class::addConstructor` support for specifying factory functor to do placement new of the object instance. +* Added `Class::addDestructor` to register a custom `__destruct` metamethod hook invoked just before the C++ destructor runs. * Added `Class::addFunction` overload taking a `lua_CFunction` as if it were a member. * Added `Class::addIndexMetaMethod` to allow register `__index` metamethod fallback on a registered class. * Added `Class::addNewIndexMetaMethod` to allow register `__newindex` metamethod fallback on a registered class. +* Added `Class::addStaticIndexMetaMethod` for fallback `__index` handling on the static class table. +* Added `Class::addStaticNewIndexMetaMethod` for fallback `__newindex` handling on the static class table. * Added `LuaRef::isValid` to check when the reference is a LUA_NOREF. * Added `LuaRef::isCallable` to check when the reference is a function or has a `__call` metamethod. * Added `LuaException::state` to return the `lua_State` associated with the exception. +* Added `void*` and `const void*` stack specializations mapped transparently to Lua lightuserdata. * Added support for `std::byte` as stack value type. * Added support for `std::string_view` as stack value type. * Added support for `std::tuple` as stack value type. * Added support for `std::optional` as stack value type. * Added support for `std::set` as stack value type by using `LuaBridge/Set.h`. * Added support to `LuaRef` for being hashed with `std::hash` (`LuaRef` properly usable in `std::unordered_map`). +* Added `LuaRef::append` and variadic `LuaRef::append(vs...)` to append values to a Lua sequence table using `lua_rawseti`. +* Added `LuaRef::call()` now returns a strongly-typed `TypeResult` instead of a generic `LuaResult`; `LuaRef::operator()` returns `TypeResult`. +* Added `LUABRIDGE_STRICT_STACK_CONVERSIONS` compile-time flag to enforce strict type-safe stack conversions (`bool` requires `LUA_TBOOLEAN`, `std::string` requires `LUA_TSTRING`). +* Added `LuaFunction` strongly-typed wrapper class for invoking Lua functions with compile-time argument and return-type checking. +* Added `TypeResult::valueOr(default)` to extract the contained value or return a fallback when a cast fails. +* Added `allowOverridingMethods` class option to permit Lua scripts to override C++ methods registered in an extensible class. * Added single header amalgamated distribution file, to simplify including in projects. * Added more asserts for functions and property names. * Renamed `luabridge::Nil` to `luabridge::LuaNil` to allow including LuaBridge in Obj-C sources. @@ -42,6 +55,8 @@ * Removed `TypeList` from loki, using parameter packs and `std::tuple` with `std::apply`. * Removed juce traces from unit tests, simplified unit tests runs. * Changed all generic functions in `LuaRef` and `TableItem` to accept arguments by const reference instead of by copy. +* Fixed `Stack::get` to properly require `LUA_TBOOLEAN` when `LUABRIDGE_STRICT_STACK_CONVERSIONS` is enabled; without the flag, legacy `lua_toboolean` semantics are preserved. +* Fixed floating-point `Stack::push`, `get`, and `isInstance` to correctly allow NaN and Inf values to pass through without error. * Fixed issue when `LuaRef::cast<>` fails with exceptions enabled, popping from the now empty stack could trigger the panic handler twice. * Fixed unaligned access in user allocated member pointers in 64bit machines reported by ASAN. * Fixed access of `LuaRef` in garbage collected `lua_thread`. @@ -49,7 +64,7 @@ * Included testing against Ravi VM * Bumped lua 5.2.x in unit tests from lua 5.2.0 to 5.2.4. * Bumped lua 5.4.x in unit tests from lua 5.4.1 to 5.4.8. -* Run against lua 5.3.6 and 5.5.0 in unit tests. +* Added Lua 5.3.6 and 5.5.0 in unit tests. * Run against PUC-Lua, Luau, LuaJIT and Ravi in CI. * Converted the manual from html to markdown. * Small improvements to code and doxygen comments readability. diff --git a/CMakeLists.txt b/CMakeLists.txt index ccee8949..b0d83295 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,7 @@ find_program (GENHTML_EXECUTABLE genhtml) cmake_dependent_option (LUABRIDGE_TESTING "Build tests" ON "CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF) cmake_dependent_option (LUABRIDGE_COVERAGE "Enable coverage" OFF "LUABRIDGE_TESTING;FIND_EXECUTABLE;LCOV_EXECUTABLE;GENHTML_EXECUTABLE" OFF) cmake_dependent_option (LUABRIDGE_BENCHMARKS "Build benchmark executable" OFF "CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF) +set (LUABRIDGE_SANITIZE "" CACHE STRING "Sanitizer to enable (address, undefined, thread)") add_subdirectory (Source) diff --git a/Distribution/LuaBridge/LuaBridge.h b/Distribution/LuaBridge/LuaBridge.h index 51d6618a..9fd5f26f 100644 --- a/Distribution/LuaBridge/LuaBridge.h +++ b/Distribution/LuaBridge/LuaBridge.h @@ -72,6 +72,12 @@ #define LUABRIDGE_IF_NO_EXCEPTIONS(...) __VA_ARGS__ #endif +#if defined(__clang__) || defined(__GNUC__) +#define LUABRIDGE_NO_SANITIZE(x) __attribute__((no_sanitize(x))) +#else +#define LUABRIDGE_NO_SANITIZE(x) +#endif + #if defined(LUAU_FASTMATH_BEGIN) #define LUABRIDGE_ON_LUAU 1 #elif defined(LUAJIT_VERSION) @@ -119,218 +125,630 @@ // End File: Source/LuaBridge/detail/Config.h -// Begin File: Source/LuaBridge/detail/LuaHelpers.h +// Begin File: Source/LuaBridge/detail/FuncTraits.h namespace luabridge { +namespace detail { -template -constexpr void unused(Args&&...) +[[noreturn]] inline void unreachable() { +#if defined(__GNUC__) + __builtin_unreachable(); +#elif defined(_MSC_VER) + __assume(false); +#endif } -#if LUA_VERSION_NUM < 502 -using lua_Unsigned = std::make_unsigned_t; - -#if ! LUABRIDGE_ON_LUAU -inline int lua_absindex(lua_State* L, int idx) +template< class T > +struct remove_cvref { - if (idx > LUA_REGISTRYINDEX && idx < 0) - return lua_gettop(L) + idx + 1; - else - return idx; -} -#endif + typedef std::remove_cv_t> type; +}; -#define LUA_OPEQ 1 -#define LUA_OPLT 2 -#define LUA_OPLE 3 +template +using remove_cvref_t = typename remove_cvref::type; -inline int lua_compare(lua_State* L, int idx1, int idx2, int op) +template +struct function_traits_base { - switch (op) - { - case LUA_OPEQ: - return lua_equal(L, idx1, idx2); - - case LUA_OPLT: - return lua_lessthan(L, idx1, idx2); + using result_type = R; - case LUA_OPLE: - return lua_equal(L, idx1, idx2) || lua_lessthan(L, idx1, idx2); + using argument_types = std::tuple; - default: - return 0; - } -} + static constexpr auto arity = sizeof...(Args); -#if ! LUABRIDGE_ON_LUAJIT -inline void* luaL_testudata(lua_State* L, int ud, const char* tname) -{ - void* p = lua_touserdata(L, ud); - if (p == nullptr) - return nullptr; + static constexpr auto is_member = IsMember; - if (! lua_getmetatable(L, ud)) - return nullptr; + static constexpr auto is_const = IsConst; +}; - luaL_getmetatable(L, tname); - if (! lua_rawequal(L, -1, -2)) - p = nullptr; +template +struct function_traits_impl; - lua_pop(L, 2); - return p; -} -#endif +template +struct function_traits_impl : function_traits_base +{ +}; -inline int get_length(lua_State* L, int idx) +template +struct function_traits_impl : function_traits_base { - return static_cast(lua_objlen(L, idx)); -} -#else -inline int get_length(lua_State* L, int idx) +}; + +template +struct function_traits_impl : function_traits_base { - return static_cast(lua_rawlen(L, idx)); -} -#endif +}; -#if LUABRIDGE_ON_LUAU -inline int luaL_ref(lua_State* L, int idx) +template +struct function_traits_impl : function_traits_base { - LUABRIDGE_ASSERT(idx == LUA_REGISTRYINDEX); +}; - const int ref = lua_ref(L, -1); +template +struct function_traits_impl : function_traits_base +{ +}; - lua_pop(L, 1); +template +struct function_traits_impl : function_traits_base +{ +}; - return ref; -} +template +struct function_traits_impl : function_traits_base +{ +}; -inline void luaL_unref(lua_State* L, int idx, int ref) +template +struct function_traits_impl : function_traits_base { - unused(idx); +}; - lua_unref(L, ref); -} +#if defined(_MSC_VER) && defined(_M_IX86) +inline static constexpr bool is_stdcall_default_calling_convention = std::is_same_v; +inline static constexpr bool is_fastcall_default_calling_convention = std::is_same_v; -template -inline void* lua_newuserdata_x(lua_State* L, size_t sz) +template +struct function_traits_impl : function_traits_base { - return lua_newuserdatadtor(L, sz, [](void* x) - { - T* object = static_cast(x); - object->~T(); - }); -} +}; -inline void lua_pushcfunction_x(lua_State *L, lua_CFunction fn, const char* debugname) +template +struct function_traits_impl : function_traits_base { - lua_pushcfunction(L, fn, debugname); -} +}; -inline void lua_pushcclosure_x(lua_State* L, lua_CFunction fn, const char* debugname, int n) +template +struct function_traits_impl : function_traits_base { - lua_pushcclosure(L, fn, debugname, n); -} +}; -inline int lua_error_x(lua_State* L) +template +struct function_traits_impl : function_traits_base { - lua_error(L); - return 0; -} +}; -inline int lua_getstack_x(lua_State* L, int level, lua_Debug* ar) +template +struct function_traits_impl : function_traits_base { - return lua_getinfo(L, level, "nlS", ar); -} +}; -inline int lua_getstack_info_x(lua_State* L, int level, const char* what, lua_Debug* ar) +template +struct function_traits_impl : function_traits_base { - return lua_getinfo(L, level, what, ar); -} +}; -inline int lua_rawgetp_x(lua_State* L, int idx, void* p) +template +struct function_traits_impl : function_traits_base { - return lua_rawgetp(L, idx, p); -} +}; -inline void lua_rawsetp_x(lua_State* L, int idx, void* p) +template +struct function_traits_impl : function_traits_base { - lua_rawsetp(L, idx, p); -} - -#else -using ::luaL_ref; -using ::luaL_unref; +}; -template -inline void* lua_newuserdata_x(lua_State* L, size_t sz) +template +struct function_traits_impl : function_traits_base { - return lua_newuserdata(L, sz); -} +}; -inline void lua_pushcfunction_x(lua_State *L, lua_CFunction fn, const char* debugname) +template +struct function_traits_impl : function_traits_base { - unused(debugname); - - lua_pushcfunction(L, fn); -} +}; -inline void lua_pushcclosure_x(lua_State* L, lua_CFunction fn, const char* debugname, int n) +template +struct function_traits_impl : function_traits_base { - unused(debugname); - - lua_pushcclosure(L, fn, n); -} +}; -inline int lua_error_x(lua_State* L) +template +struct function_traits_impl : function_traits_base { - return lua_error(L); -} +}; -inline int lua_getstack_x(lua_State* L, int level, lua_Debug* ar) +template +struct function_traits_impl : function_traits_base { - return lua_getstack(L, level, ar); -} +}; -inline int lua_getstack_info_x(lua_State* L, int level, const char* what, lua_Debug* ar) +template +struct function_traits_impl : function_traits_base { - lua_getstack(L, level, ar); - return lua_getinfo(L, what, ar); -} +}; -inline int lua_rawgetp_x(lua_State* L, int idx, void* p) +template +struct function_traits_impl : function_traits_base { -#if LUA_VERSION_NUM < 503 - idx = lua_absindex(L, idx); - luaL_checkstack(L, 1, "not enough stack slots"); - lua_pushlightuserdata(L, p); - lua_rawget(L, idx); - return lua_type(L, -1); -#else - return lua_rawgetp(L, idx, p); -#endif -} +}; -inline void lua_rawsetp_x(lua_State* L, int idx, void* p) +template +struct function_traits_impl : function_traits_base { -#if LUA_VERSION_NUM < 503 - idx = lua_absindex(L, idx); - luaL_checkstack(L, 1, "not enough stack slots"); - lua_pushlightuserdata(L, p); - lua_insert(L, -2); - lua_rawset(L, idx); -#else - lua_rawsetp(L, idx, p); +}; #endif -} -#endif - -#if LUA_VERSION_NUM < 505 -inline lua_State* lua_newstate_x(lua_Alloc f, void* ud, [[maybe_unused]] unsigned seed) +template +struct functor_traits_impl : function_traits_impl { - return lua_newstate(f, ud); -} +}; + +template +struct function_traits : std::conditional_t, + detail::functor_traits_impl, + detail::function_traits_impl> +{ +}; + +template +struct function_argument_or_void +{ + using type = void; +}; + +template +struct function_argument_or_void::argument_types>>> +{ + using type = std::tuple_element_t::argument_types>; +}; + +template +using function_argument_or_void_t = typename function_argument_or_void::type; + +template +using function_result_t = typename function_traits::result_type; + +template +using function_argument_t = std::tuple_element_t::argument_types>; + +template +using function_arguments_t = typename function_traits::argument_types; + +template +static constexpr std::size_t function_arity_v = function_traits::arity; + +template +static constexpr bool function_is_member_v = function_traits::is_member; + +template +static constexpr bool function_is_const_v = function_traits::is_const; + +template +struct is_callable +{ + static constexpr bool value = false; +}; + +template +struct is_callable> +{ + static constexpr bool value = true; +}; + +template +struct is_callable && std::is_function_v>>> +{ + static constexpr bool value = true; +}; + +template +struct is_callable>> +{ + static constexpr bool value = true; +}; + +template +inline static constexpr bool is_callable_v = is_callable::value; + +template +struct is_const_member_function_pointer +{ + static constexpr bool value = false; +}; + +template +struct is_const_member_function_pointer +{ + static constexpr bool value = false; +}; + +template +struct is_const_member_function_pointer +{ + static constexpr bool value = true; +}; + +template +struct is_const_member_function_pointer +{ + static constexpr bool value = false; +}; + +template +struct is_const_member_function_pointer +{ + static constexpr bool value = true; +}; + +template +inline static constexpr bool is_const_member_function_pointer_v = is_const_member_function_pointer::value; + +template +struct is_cfunction_pointer +{ + static constexpr bool value = false; +}; + +template <> +struct is_cfunction_pointer +{ + static constexpr bool value = true; +}; + +template +inline static constexpr bool is_cfunction_pointer_v = is_cfunction_pointer::value; + +template +struct is_member_cfunction_pointer +{ + static constexpr bool value = false; +}; + +template +struct is_member_cfunction_pointer +{ + static constexpr bool value = true; +}; + +template +struct is_member_cfunction_pointer +{ + static constexpr bool value = true; +}; + +template +inline static constexpr bool is_member_cfunction_pointer_v = is_member_cfunction_pointer::value; + +template +struct is_const_member_cfunction_pointer +{ + static constexpr bool value = false; +}; + +template +struct is_const_member_cfunction_pointer +{ + static constexpr bool value = false; +}; + +template +struct is_const_member_cfunction_pointer +{ + static constexpr bool value = true; +}; + +template +inline static constexpr bool is_const_member_cfunction_pointer_v = is_const_member_cfunction_pointer::value; + +template +inline static constexpr bool is_any_cfunction_pointer_v = is_cfunction_pointer_v || is_member_cfunction_pointer_v; + +template +inline static constexpr bool is_proxy_member_function_v = + !std::is_member_function_pointer_v && + std::is_same_v>>>; + +template +inline static constexpr bool is_const_proxy_function_v = + is_proxy_member_function_v && + std::is_const_v>>>; + +template +struct function_arity_excluding +{ +}; + +template < class... Ts, class ExclusionType> +struct function_arity_excluding, ExclusionType> + : std::integral_constant, ExclusionType> ? 0 : 1))> +{ +}; + +template +inline static constexpr std::size_t function_arity_excluding_v = function_arity_excluding, ExclusionType>::value; + +template +struct member_function_arity_excluding +{ +}; + +template +struct member_function_arity_excluding, ExclusionType, std::enable_if_t>> + : std::integral_constant, ExclusionType> ? 0 : 1))> +{ +}; + +template +struct member_function_arity_excluding, ExclusionType, std::enable_if_t>> + : std::integral_constant, ExclusionType> ? 0 : 1)) - 1> +{ +}; + +template +inline static constexpr std::size_t member_function_arity_excluding_v = member_function_arity_excluding, ExclusionType>::value; + +template +static constexpr bool is_const_function = + detail::is_const_member_function_pointer_v || + (detail::function_arity_v > 0 && detail::is_const_proxy_function_v); + +template +inline static constexpr std::size_t const_functions_count = (0 + ... + (is_const_function ? 1 : 0)); + +template +inline static constexpr std::size_t non_const_functions_count = (0 + ... + (is_const_function ? 0 : 1)); + +template +constexpr auto tupleize(Types&&... types) +{ + return std::tuple(std::forward(types)...); +} + +template +struct remove_first_type +{ +}; + +template +struct remove_first_type> +{ + using type = std::tuple; +}; + +template +using remove_first_type_t = typename remove_first_type::type; + +} +} + + +// End File: Source/LuaBridge/detail/FuncTraits.h + +// Begin File: Source/LuaBridge/detail/LuaHelpers.h + +namespace luabridge { + +template +constexpr void unused(Args&&...) +{ +} + +#if LUA_VERSION_NUM < 502 +using lua_Unsigned = std::make_unsigned_t; + +#if ! LUABRIDGE_ON_LUAU +inline int lua_absindex(lua_State* L, int idx) +{ + if (idx > LUA_REGISTRYINDEX && idx < 0) + return lua_gettop(L) + idx + 1; + else + return idx; +} +#endif + +#define LUA_OPEQ 1 +#define LUA_OPLT 2 +#define LUA_OPLE 3 + +inline int lua_compare(lua_State* L, int idx1, int idx2, int op) +{ + switch (op) + { + case LUA_OPEQ: + return lua_equal(L, idx1, idx2); + + case LUA_OPLT: + return lua_lessthan(L, idx1, idx2); + + case LUA_OPLE: + return lua_equal(L, idx1, idx2) || lua_lessthan(L, idx1, idx2); + + default: + return 0; + } +} + +#if ! LUABRIDGE_ON_LUAJIT +inline void* luaL_testudata(lua_State* L, int ud, const char* tname) +{ + void* p = lua_touserdata(L, ud); + if (p == nullptr) + return nullptr; + + if (! lua_getmetatable(L, ud)) + return nullptr; + + luaL_getmetatable(L, tname); + if (! lua_rawequal(L, -1, -2)) + p = nullptr; + + lua_pop(L, 2); + return p; +} +#endif + +inline int get_length(lua_State* L, int idx) +{ + return static_cast(lua_objlen(L, idx)); +} +#else +inline int get_length(lua_State* L, int idx) +{ + return static_cast(lua_rawlen(L, idx)); +} +#endif + +#if LUABRIDGE_ON_LUAU +inline int luaL_ref(lua_State* L, int idx) +{ + LUABRIDGE_ASSERT(idx == LUA_REGISTRYINDEX); + + const int ref = lua_ref(L, -1); + + lua_pop(L, 1); + + return ref; +} + +inline void luaL_unref(lua_State* L, int idx, int ref) +{ + unused(idx); + + lua_unref(L, ref); +} + +template +inline void* lua_newuserdata_x(lua_State* L, size_t sz) +{ + return lua_newuserdatadtor(L, sz, [](void* x) + { + T* object = static_cast(x); + object->~T(); + }); +} + +inline void lua_pushcfunction_x(lua_State *L, lua_CFunction fn, const char* debugname) +{ + lua_pushcfunction(L, fn, debugname); +} + +inline void lua_pushcclosure_x(lua_State* L, lua_CFunction fn, const char* debugname, int n) +{ + lua_pushcclosure(L, fn, debugname, n); +} + +[[noreturn]] inline void lua_error_x(lua_State* L) +{ + lua_error(L); +} + +inline int lua_getstack_x(lua_State* L, int level, lua_Debug* ar) +{ + return lua_getinfo(L, level, "nlS", ar); +} + +inline int lua_getstack_info_x(lua_State* L, int level, const char* what, lua_Debug* ar) +{ + return lua_getinfo(L, level, what, ar); +} + +inline int lua_rawgetp_x(lua_State* L, int idx, void* p) +{ + return lua_rawgetp(L, idx, p); +} + +inline void lua_rawsetp_x(lua_State* L, int idx, void* p) +{ + lua_rawsetp(L, idx, p); +} + +#else +using ::luaL_ref; +using ::luaL_unref; + +template +inline void* lua_newuserdata_x(lua_State* L, size_t sz) +{ + return lua_newuserdata(L, sz); +} + +inline void lua_pushcfunction_x(lua_State *L, lua_CFunction fn, const char* debugname) +{ + unused(debugname); + + lua_pushcfunction(L, fn); +} + +inline void lua_pushcclosure_x(lua_State* L, lua_CFunction fn, const char* debugname, int n) +{ + unused(debugname); + + lua_pushcclosure(L, fn, n); +} + +[[noreturn]] inline void lua_error_x(lua_State* L) +{ + lua_error(L); + + detail::unreachable(); +} + +inline int lua_getstack_x(lua_State* L, int level, lua_Debug* ar) +{ + return lua_getstack(L, level, ar); +} + +inline int lua_getstack_info_x(lua_State* L, int level, const char* what, lua_Debug* ar) +{ + lua_getstack(L, level, ar); + return lua_getinfo(L, what, ar); +} + +inline int lua_rawgetp_x(lua_State* L, int idx, void* p) +{ +#if LUA_VERSION_NUM < 503 + idx = lua_absindex(L, idx); + luaL_checkstack(L, 1, "not enough stack slots"); + lua_pushlightuserdata(L, p); + lua_rawget(L, idx); + return lua_type(L, -1); +#else + return lua_rawgetp(L, idx, p); +#endif +} + +inline void lua_rawsetp_x(lua_State* L, int idx, void* p) +{ +#if LUA_VERSION_NUM < 503 + idx = lua_absindex(L, idx); + luaL_checkstack(L, 1, "not enough stack slots"); + lua_pushlightuserdata(L, p); + lua_insert(L, -2); + lua_rawset(L, idx); +#else + lua_rawsetp(L, idx, p); +#endif +} + +#endif + +#if LUA_VERSION_NUM < 505 +inline lua_State* lua_newstate_x(lua_Alloc f, void* ud, [[maybe_unused]] unsigned seed) +{ + return lua_newstate(f, ud); +} #else inline lua_State* lua_newstate_x(lua_Alloc f, void* ud, unsigned seed) { @@ -357,7 +775,7 @@ inline lua_Integer to_integerx(lua_State* L, int idx, int* isnum) if (ok) { if (n < static_cast(std::numeric_limits::min()) || - n > static_cast(std::numeric_limits::max())) + n >= -static_cast(std::numeric_limits::min())) { if (isnum) *isnum = 0; @@ -603,7 +1021,7 @@ void* lua_newuserdata_aligned(lua_State* L, Args&&... args) return pointer; } -inline int raise_lua_error(lua_State* L, const char* fmt, ...) +[[noreturn]] inline void raise_lua_error(lua_State* L, const char* fmt, ...) { va_list argp; va_start(argp, fmt); @@ -614,7 +1032,7 @@ inline int raise_lua_error(lua_State* L, const char* fmt, ...) if (message != nullptr) { if (auto str = std::string_view(message); !str.empty() && str[0] == '[') - return lua_error_x(L); + lua_error_x(L); } bool pushed_error = false; @@ -646,7 +1064,7 @@ inline int raise_lua_error(lua_State* L, const char* fmt, ...) lua_remove(L, -3); lua_concat(L, 2); - return lua_error_x(L); + lua_error_x(L); } template @@ -2113,239 +2531,10 @@ class Expected : public detail::expected_base - constexpr T valueOr(U&& defaultValue) const& - { - return hasValue() ? value() : static_cast(std::forward(defaultValue)); - } - - template - T valueOr(U&& defaultValue) && - { - return hasValue() ? std::move(value()) : static_cast(std::forward(defaultValue)); - } - -private: - template - auto assign(Tag tag, Args&&... args) noexcept(noexcept(std::declval().destroy()) && noexcept(std::declval().construct(tag, std::forward(args)...))) - -> decltype(std::declval().construct(tag, std::forward(args)...)) - { - this->destroy(); - - return this->construct(tag, std::forward(args)...); - } -}; - -template -class Expected : public detail::expected_base, std::is_move_constructible_v> -{ - static_assert(!std::is_reference_v && !std::is_void_v, "Unexpected type can't be a reference or void"); - - using base_type = detail::expected_base, std::is_move_constructible_v>; - using this_type = Expected; - -public: - using value_type = void; - - using error_type = E; - - using unexpected_type = Unexpected; - - template - struct rebind - { - using type = Expected; - }; - - constexpr Expected() = default; - - constexpr Expected(const Expected& other) = default; - - constexpr Expected(Expected&& other) = default; - - template - Expected(const Expected& other) - { - if (other.hasValue()) - { - this->valid_ = true; - } - else - { - this->construct(unexpect, other.error()); - } - } - - template - Expected(Expected&& other) - { - if (other.hasValue()) - { - this->valid_ = true; - } - else - { - this->construct(unexpect, std::move(other.error())); - } - } - - template - constexpr Expected(const Unexpected& u) - : base_type(unexpect, u.value()) - { - } - - template - constexpr Expected(Unexpected&& u) - : base_type(unexpect, std::move(u.value())) - { - } - - template - constexpr explicit Expected(UnexpectType, Args&&... args) - : base_type(unexpect, std::forward(args)...) - { - } - - template - constexpr explicit Expected(UnexpectType, std::initializer_list ilist, Args&&... args) - : base_type(unexpect, ilist, std::forward(args)...) - { - } - - Expected& operator=(const Expected& other) - { - if (other.hasValue()) - { - assign(std::in_place); - } - else - { - assign(unexpect, other.error()); - } - - return *this; - } - - Expected& operator=(Expected&& other) - { - if (other.hasValue()) - { - assign(std::in_place); - } - else - { - assign(unexpect, std::move(other.error())); - } - - return *this; - } - - template - Expected& operator=(const Unexpected& u) - { - assign(unexpect, u.value()); - return *this; - } - - template - Expected& operator=(Unexpected&& u) - { - assign(unexpect, std::move(u.value())); - return *this; - } - - void swap(Expected& other) noexcept(detail::is_nothrow_swappable::value) - { - using std::swap; - - if (hasValue()) - { - if (!other.hasValue()) - { - assign(unexpect, std::move(other.error())); - other.assign(std::in_place); - } - } - else - { - if (other.hasValue()) - { - other.swap(*this); - } - else - { - swap(error(), other.error()); - } - } + + constexpr T&& operator*() && + { + return std::move(value()); } constexpr explicit operator bool() const noexcept @@ -2358,2996 +2547,2800 @@ class Expected : public detail::expected_base - void assign(Tag tag, Args&&... args) noexcept(noexcept(std::declval().destroy()) && noexcept(std::declval().construct(tag, std::forward(args)...))) + constexpr const T&& value() const&& LUABRIDGE_IF_NO_EXCEPTIONS(noexcept) { - this->destroy(); - this->construct(tag, std::forward(args)...); - } -}; - -template -constexpr bool operator==(const Expected& lhs, const Expected& rhs) -{ - return (lhs && rhs) ? *lhs == *rhs : ((!lhs && !rhs) ? lhs.error() == rhs.error() : false); -} - -template -constexpr bool operator==(const Expected& lhs, const Expected& rhs) -{ - return (lhs && rhs) ? true : ((!lhs && !rhs) ? lhs.error() == rhs.error() : false); -} - -template -constexpr bool operator!=(const Expected& lhs, const Expected& rhs) -{ - return !(lhs == rhs); -} - -template -constexpr bool operator==(const Expected& lhs, const T& rhs) -{ - return lhs ? *lhs == rhs : false; -} - -template -constexpr bool operator==(const T& lhs, const Expected& rhs) -{ - return rhs == lhs; -} - -template -constexpr bool operator!=(const Expected& lhs, const T& rhs) -{ - return !(lhs == rhs); -} - -template -constexpr bool operator!=(const T& lhs, const Expected& rhs) -{ - return rhs != lhs; -} - -template -constexpr bool operator==(const Expected& lhs, const Unexpected& rhs) -{ - return lhs ? false : lhs.error() == rhs.value(); -} - -template -constexpr bool operator==(const Unexpected& lhs, const Expected& rhs) -{ - return rhs == lhs; -} - -template -constexpr bool operator!=(const Expected& lhs, const Unexpected& rhs) -{ - return !(lhs == rhs); -} - -template -constexpr bool operator!=(const Unexpected& lhs, const Expected& rhs) -{ - return rhs != lhs; -} -} - - -// End File: Source/LuaBridge/detail/Expected.h - -// Begin File: Source/LuaBridge/detail/Result.h - -namespace luabridge { + if (!hasValue()) + detail::throw_bad_expected_access_or_abort(std::move(error())); -struct Result -{ - Result() noexcept = default; + return std::move(base_type::value()); + } - Result(std::error_code ec) noexcept - : m_ec(ec) + constexpr T&& value() && LUABRIDGE_IF_NO_EXCEPTIONS(noexcept) { - } + if (!hasValue()) + detail::throw_bad_expected_access_or_abort(std::move(error())); - Result(const Result&) noexcept = default; - Result(Result&&) noexcept = default; - Result& operator=(const Result&) noexcept = default; - Result& operator=(Result&&) noexcept = default; + return std::move(base_type::value()); + } - explicit operator bool() const noexcept + constexpr const E& error() const& noexcept { - return !m_ec; + return base_type::error(); } - std::error_code error() const noexcept + constexpr E& error() & noexcept { - return m_ec; + return base_type::error(); } - const char* error_cstr() const noexcept + constexpr const E&& error() const&& noexcept { - return detail::ErrorCategory::errorString(m_ec.value()); + return std::move(base_type::error()); } - operator std::error_code() const noexcept + constexpr E&& error() && noexcept { - return m_ec; + return std::move(base_type::error()); } - std::string message() const + template + constexpr T valueOr(U&& defaultValue) const& { - return m_ec.message(); + return hasValue() ? value() : static_cast(std::forward(defaultValue)); } -#if LUABRIDGE_HAS_EXCEPTIONS - void throw_on_error() const + template + T valueOr(U&& defaultValue) && { - if (m_ec) - throw std::system_error(m_ec); + return hasValue() ? std::move(value()) : static_cast(std::forward(defaultValue)); } -#endif private: - std::error_code m_ec; + template + auto assign(Tag tag, Args&&... args) noexcept(noexcept(std::declval().destroy()) && noexcept(std::declval().construct(tag, std::forward(args)...))) + -> decltype(std::declval().construct(tag, std::forward(args)...)) + { + this->destroy(); + + return this->construct(tag, std::forward(args)...); + } }; -template -struct TypeResult +template +class Expected : public detail::expected_base, std::is_move_constructible_v> { - TypeResult() noexcept = default; + static_assert(!std::is_reference_v && !std::is_void_v, "Unexpected type can't be a reference or void"); - template && !std::is_same_v, std::error_code>>> - TypeResult(U&& value) noexcept - : m_value(std::in_place, std::forward(value)) - { - } + using base_type = detail::expected_base, std::is_move_constructible_v>; + using this_type = Expected; - TypeResult(std::error_code ec) noexcept - : m_value(makeUnexpected(ec)) - { - } +public: + using value_type = void; - TypeResult(const TypeResult&) = default; - TypeResult(TypeResult&&) = default; - TypeResult& operator=(const TypeResult&) = default; - TypeResult& operator=(TypeResult&&) = default; + using error_type = E; - explicit operator bool() const noexcept - { - return m_value.hasValue(); - } + using unexpected_type = Unexpected; - const T& value() const + template + struct rebind { - return m_value.value(); - } + using type = Expected; + }; - T& operator*() & - { - return m_value.value(); - } + constexpr Expected() = default; - T operator*() && - { - return std::move(m_value.value()); - } + constexpr Expected(const Expected& other) = default; - const T& operator*() const& + constexpr Expected(Expected&& other) = default; + + template + Expected(const Expected& other) { - return m_value.value(); + if (other.hasValue()) + { + this->valid_ = true; + } + else + { + this->construct(unexpect, other.error()); + } } - T operator*() const&& + template + Expected(Expected&& other) { - return std::move(m_value.value()); + if (other.hasValue()) + { + this->valid_ = true; + } + else + { + this->construct(unexpect, std::move(other.error())); + } } - template - T valueOr(U&& defaultValue) const& + template + constexpr Expected(const Unexpected& u) + : base_type(unexpect, u.value()) { - return m_value.valueOr(std::forward(defaultValue)); } - template - T valueOr(U&& defaultValue) && + template + constexpr Expected(Unexpected&& u) + : base_type(unexpect, std::move(u.value())) { - return m_value.valueOr(std::forward(defaultValue)); } - std::error_code error() const + template + constexpr explicit Expected(UnexpectType, Args&&... args) + : base_type(unexpect, std::forward(args)...) { - return m_value.error(); } - const char* error_cstr() const noexcept + template + constexpr explicit Expected(UnexpectType, std::initializer_list ilist, Args&&... args) + : base_type(unexpect, ilist, std::forward(args)...) { - return detail::ErrorCategory::errorString(m_value.error().value()); } - operator std::error_code() const + Expected& operator=(const Expected& other) { - return m_value.error(); + if (other.hasValue()) + { + assign(std::in_place); + } + else + { + assign(unexpect, other.error()); + } + + return *this; } - std::string message() const + Expected& operator=(Expected&& other) { - return m_value.error().message(); + if (other.hasValue()) + { + assign(std::in_place); + } + else + { + assign(unexpect, std::move(other.error())); + } + + return *this; } -#if LUABRIDGE_HAS_EXCEPTIONS - void throw_on_error() const + template + Expected& operator=(const Unexpected& u) { - if (! m_value.hasValue()) - throw std::system_error(m_value.error()); + assign(unexpect, u.value()); + return *this; } -#endif - -private: - Expected m_value; -}; -template <> -struct TypeResult -{ - TypeResult() noexcept = default; - - TypeResult(std::error_code ec) noexcept - : m_ec(ec) + template + Expected& operator=(Unexpected&& u) { + assign(unexpect, std::move(u.value())); + return *this; } - TypeResult(const TypeResult&) noexcept = default; - TypeResult(TypeResult&&) noexcept = default; - TypeResult& operator=(const TypeResult&) noexcept = default; - TypeResult& operator=(TypeResult&&) noexcept = default; - - explicit operator bool() const noexcept + void swap(Expected& other) noexcept(detail::is_nothrow_swappable::value) { - return ! m_ec; + using std::swap; + + if (hasValue()) + { + if (!other.hasValue()) + { + assign(unexpect, std::move(other.error())); + other.assign(std::in_place); + } + } + else + { + if (other.hasValue()) + { + other.swap(*this); + } + else + { + swap(error(), other.error()); + } + } } - void value() const noexcept + constexpr explicit operator bool() const noexcept { + return hasValue(); } - std::error_code error() const noexcept + constexpr bool hasValue() const noexcept { - return m_ec; + return base_type::valid(); } - const char* error_cstr() const noexcept + constexpr const E& error() const& noexcept { - return detail::ErrorCategory::errorString(m_ec.value()); + return base_type::error(); } - operator std::error_code() const noexcept + constexpr E& error() & noexcept { - return m_ec; + return base_type::error(); } - std::string message() const + constexpr const E&& error() const&& noexcept { - return m_ec.message(); + return std::move(base_type::error()); } -#if LUABRIDGE_HAS_EXCEPTIONS - void throw_on_error() const + constexpr E&& error() && noexcept { - if (m_ec) - throw std::system_error(m_ec); + return std::move(base_type::error()); } -#endif private: - std::error_code m_ec; + template + void assign(Tag tag, Args&&... args) noexcept(noexcept(std::declval().destroy()) && noexcept(std::declval().construct(tag, std::forward(args)...))) + { + this->destroy(); + this->construct(tag, std::forward(args)...); + } }; -template -inline bool operator==(const TypeResult& lhs, const U& rhs) noexcept +template +constexpr bool operator==(const Expected& lhs, const Expected& rhs) { - return lhs ? *lhs == rhs : false; + return (lhs && rhs) ? *lhs == *rhs : ((!lhs && !rhs) ? lhs.error() == rhs.error() : false); } -template -inline bool operator==(const U& lhs, const TypeResult& rhs) noexcept +template +constexpr bool operator==(const Expected& lhs, const Expected& rhs) { - return rhs == lhs; + return (lhs && rhs) ? true : ((!lhs && !rhs) ? lhs.error() == rhs.error() : false); } -template -inline bool operator!=(const TypeResult& lhs, const U& rhs) noexcept +template +constexpr bool operator!=(const Expected& lhs, const Expected& rhs) { return !(lhs == rhs); } -template -inline bool operator!=(const U& lhs, const TypeResult& rhs) noexcept -{ - return !(rhs == lhs); -} - -} - - -// End File: Source/LuaBridge/detail/Result.h - -// Begin File: Source/LuaBridge/detail/ClassInfo.h - -#if defined __clang__ || defined __GNUC__ -#define LUABRIDGE_PRETTY_FUNCTION __PRETTY_FUNCTION__ -#define LUABRIDGE_PRETTY_FUNCTION_PREFIX '=' -#define LUABRIDGE_PRETTY_FUNCTION_SUFFIX ']' -#elif defined _MSC_VER -#define LUABRIDGE_PRETTY_FUNCTION __FUNCSIG__ -#define LUABRIDGE_PRETTY_FUNCTION_PREFIX '<' -#define LUABRIDGE_PRETTY_FUNCTION_SUFFIX '>' -#endif - -namespace luabridge { -namespace detail { - -[[nodiscard]] constexpr auto fnv1a(const char* s, std::size_t count) noexcept -{ - uint32_t seed = 2166136261u; - - for (std::size_t i = 0; i < count; ++i) - seed = static_cast(static_cast(seed ^ static_cast(*s++)) * 16777619u); - - if constexpr (sizeof(void*) == 8) - return static_cast(seed); - else - return seed; -} - -template -[[nodiscard]] static constexpr auto typeName(T* = nullptr) noexcept -{ - constexpr std::string_view prettyName{ LUABRIDGE_PRETTY_FUNCTION }; - - constexpr auto first = prettyName.find_first_not_of(' ', prettyName.find_first_of(LUABRIDGE_PRETTY_FUNCTION_PREFIX) + 1); - - return prettyName.substr(first, prettyName.find_last_of(LUABRIDGE_PRETTY_FUNCTION_SUFFIX) - first); -} - -template ().find_first_of('.')> -[[nodiscard]] static constexpr auto typeHash(T* = nullptr) noexcept -{ - constexpr auto stripped = typeName(); - - return fnv1a(stripped.data(), stripped.size()); -} - -[[nodiscard]] inline void* getExceptionsKey() noexcept -{ - return reinterpret_cast(0xc7); -} - -[[nodiscard]] inline const void* getTypeKey() noexcept -{ - return reinterpret_cast(0x71); -} - -[[nodiscard]] inline const void* getConstKey() noexcept -{ - return reinterpret_cast(0xc07); -} - -[[nodiscard]] inline const void* getClassKey() noexcept -{ - return reinterpret_cast(0xc1a); -} - -[[nodiscard]] inline const void* getClassOptionsKey() noexcept -{ - return reinterpret_cast(0xc2b); -} - -[[nodiscard]] inline const void* getTypeIdentityKey() noexcept -{ - return reinterpret_cast(0xc2c); -} - -[[nodiscard]] inline const void* getPropgetKey() noexcept -{ - return reinterpret_cast(0x6e7); -} - -[[nodiscard]] inline const void* getPropsetKey() noexcept -{ - return reinterpret_cast(0x5e7); -} - -[[nodiscard]] inline const void* getStaticKey() noexcept -{ - return reinterpret_cast(0x57a); -} - -[[nodiscard]] inline const void* getParentKey() noexcept -{ - return reinterpret_cast(0xdad); -} - -[[nodiscard]] inline const void* getIndexFallbackKey() -{ - return reinterpret_cast(0x81ca); -} - -[[nodiscard]] inline const void* getIndexExtensibleKey() -{ - return reinterpret_cast(0x81cb); -} - -[[nodiscard]] inline const void* getNewIndexFallbackKey() +template +constexpr bool operator==(const Expected& lhs, const T& rhs) { - return reinterpret_cast(0x8107); + return lhs ? *lhs == rhs : false; } -[[nodiscard]] inline const void* getNewIndexExtensibleKey() +template +constexpr bool operator==(const T& lhs, const Expected& rhs) { - return reinterpret_cast(0x8108); + return rhs == lhs; } -[[nodiscard]] inline const void* getStaticIndexFallbackKey() +template +constexpr bool operator!=(const Expected& lhs, const T& rhs) { - return reinterpret_cast(0x81cc); + return !(lhs == rhs); } -[[nodiscard]] inline const void* getStaticNewIndexFallbackKey() +template +constexpr bool operator!=(const T& lhs, const Expected& rhs) { - return reinterpret_cast(0x8109); + return rhs != lhs; } -template -[[nodiscard]] const void* getStaticRegistryKey() noexcept +template +constexpr bool operator==(const Expected& lhs, const Unexpected& rhs) { - static auto value = typeHash(); - - return reinterpret_cast(value); + return lhs ? false : lhs.error() == rhs.value(); } -template -[[nodiscard]] const void* getClassRegistryKey() noexcept +template +constexpr bool operator==(const Unexpected& lhs, const Expected& rhs) { - static auto value = typeHash() ^ 1; - - return reinterpret_cast(value); + return rhs == lhs; } -template -[[nodiscard]] const void* getConstRegistryKey() noexcept +template +constexpr bool operator!=(const Expected& lhs, const Unexpected& rhs) { - static auto value = typeHash() ^ 2; + return !(lhs == rhs); +} - return reinterpret_cast(value); +template +constexpr bool operator!=(const Unexpected& lhs, const Expected& rhs) +{ + return rhs != lhs; } } -} -// End File: Source/LuaBridge/detail/ClassInfo.h +// End File: Source/LuaBridge/detail/Expected.h -// Begin File: Source/LuaBridge/detail/LuaException.h +// Begin File: Source/LuaBridge/detail/Result.h namespace luabridge { -class LuaException : public std::exception +struct Result { -public: - - LuaException(lua_State* L, std::error_code code) - : m_L(L) - , m_code(code) - { - } + Result() noexcept = default; - ~LuaException() noexcept override + Result(std::error_code ec) noexcept + : m_ec(ec) { } - const char* what() const noexcept override - { - return m_what.c_str(); - } + Result(const Result&) noexcept = default; + Result(Result&&) noexcept = default; + Result& operator=(const Result&) noexcept = default; + Result& operator=(Result&&) noexcept = default; - static void raise(lua_State* L, std::error_code code) + explicit operator bool() const noexcept { - LUABRIDGE_ASSERT(areExceptionsEnabled(L)); - -#if LUABRIDGE_HAS_EXCEPTIONS - throw LuaException(L, code, FromLua{}); -#else - unused(L, code); - - std::abort(); -#endif + return !m_ec; } - static bool areExceptionsEnabled(lua_State* L) noexcept + std::error_code error() const noexcept { - lua_pushlightuserdata(L, detail::getExceptionsKey()); - lua_gettable(L, LUA_REGISTRYINDEX); - - const bool enabled = lua_isboolean(L, -1) ? static_cast(lua_toboolean(L, -1)) : false; - lua_pop(L, 1); - - return enabled; + return m_ec; } - static void enableExceptions(lua_State* L) noexcept + const char* error_cstr() const noexcept { - lua_pushlightuserdata(L, detail::getExceptionsKey()); - lua_pushboolean(L, true); - lua_settable(L, LUA_REGISTRYINDEX); - -#if LUABRIDGE_HAS_EXCEPTIONS && LUABRIDGE_ON_LUAJIT - lua_pushlightuserdata(L, (void*)luajitWrapperCallback); - luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_ON); - lua_pop(L, 1); -#endif - -#if LUABRIDGE_ON_LUAU - auto callbacks = lua_callbacks(L); - callbacks->panic = +[](lua_State* L, int) { panicHandlerCallback(L); }; -#else - lua_atpanic(L, panicHandlerCallback); -#endif + return detail::ErrorCategory::errorString(m_ec.value()); } - lua_State* state() const { return m_L; } - -private: - struct FromLua {}; - - LuaException(lua_State* L, std::error_code code, FromLua) - : m_L(L) - , m_code(code) + operator std::error_code() const noexcept { - whatFromStack(); + return m_ec; } - void whatFromStack() + std::string message() const { - std::stringstream ss; - - const char* errorText = nullptr; - - if (lua_gettop(m_L) > 0) - { - errorText = lua_tostring(m_L, -1); - lua_pop(m_L, 1); - } - - ss << (errorText ? errorText : "Unknown error") << " (code=" << m_code.message() << ")"; - - m_what = std::move(ss).str(); + return m_ec.message(); } - static int panicHandlerCallback(lua_State* L) - { #if LUABRIDGE_HAS_EXCEPTIONS - throw LuaException(L, makeErrorCode(ErrorCode::LuaFunctionCallFailed), FromLua{}); -#else - unused(L); - - std::abort(); -#endif - } - -#if LUABRIDGE_HAS_EXCEPTIONS && LUABRIDGE_ON_LUAJIT - static int luajitWrapperCallback(lua_State* L, lua_CFunction f) + void throw_on_error() const { - try - { - return f(L); - } - catch (const std::exception& e) - { - lua_pushstring(L, e.what()); - return lua_error_x(L); - } + if (m_ec) + throw std::system_error(m_ec); } #endif - lua_State* m_L = nullptr; - std::error_code m_code; - std::string m_what; +private: + std::error_code m_ec; }; -inline void enableExceptions(lua_State* L) noexcept +template +struct TypeResult { -#if LUABRIDGE_HAS_EXCEPTIONS - LuaException::enableExceptions(L); -#else - unused(L); - - LUABRIDGE_ASSERT(false); -#endif -} - -} - - -// End File: Source/LuaBridge/detail/LuaException.h + TypeResult() noexcept = default; -// Begin File: Source/LuaBridge/detail/TypeTraits.h + template && !std::is_same_v, std::error_code>>> + TypeResult(U&& value) noexcept + : m_value(std::in_place, std::forward(value)) + { + } -namespace luabridge { -namespace detail { -template