name: CI

on:
  push:
    branches: ["**"]
  pull_request:

jobs:
  rust-macos-aarch64:
    runs-on: macos-14

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Rust
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: aarch64-apple-darwin
          components: rustfmt, clippy

      - name: Setup CMake 3.x (keystone build compatibility)
        uses: jwlawson/actions-setup-cmake@v2
        with:
          cmake-version: '3.31.6'

      - name: Setup Rust cache
        uses: Swatinem/rust-cache@v2

      - name: Cargo fmt
        run: cargo fmt --all -- --check

      - name: Cargo check
        run: cargo check --all-targets --target aarch64-apple-darwin

      - name: Cargo test
        run: cargo test --doc --target aarch64-apple-darwin

      - name: Cargo clippy
        run: cargo clippy --all-targets --target aarch64-apple-darwin -- -D warnings

      - name: Build all examples (macOS, patch_asm enabled)
        run: cargo build --examples --features patch_asm --target aarch64-apple-darwin

      - name: Run macOS example smoke tests
        shell: bash
        run: |
          set -euo pipefail

          cc -O0 -fno-inline examples/instrument_with_original/target.c -o examples/instrument_with_original/app
          DYLIB="$PWD/target/aarch64-apple-darwin/debug/examples/libinstrument_with_original.dylib"
          OUT=$(DYLD_INSERT_LIBRARIES="$DYLIB" examples/instrument_with_original/app)
          echo "$OUT"
          [[ "$OUT" == *"calc(1, 2) = 42"* ]]

          cc -O0 -fno-inline examples/instrument_no_original/target.c -o examples/instrument_no_original/app
          DYLIB="$PWD/target/aarch64-apple-darwin/debug/examples/libinstrument_no_original.dylib"
          OUT=$(DYLD_INSERT_LIBRARIES="$DYLIB" examples/instrument_no_original/app)
          echo "$OUT"
          [[ "$OUT" == *"calc(4, 5) = 99"* ]]

          cc -O0 -fno-inline examples/instrument_unhook_restore/target.c -o examples/instrument_unhook_restore/app
          DYLIB="$PWD/target/aarch64-apple-darwin/debug/examples/libinstrument_unhook_restore.dylib"
          OUT=$(DYLD_INSERT_LIBRARIES="$DYLIB" examples/instrument_unhook_restore/app)
          echo "$OUT"
          [[ "$OUT" == *"hooked_calc(3, 4) = 123"* ]]
          [[ "$OUT" == *"calc(3, 4) = 7"* ]]

          cc -O0 -fno-inline examples/inline_hook_far/target.c -o examples/inline_hook_far/app
          DYLIB="$PWD/target/aarch64-apple-darwin/debug/examples/libinline_hook_far.dylib"
          OUT=$(DYLD_INSERT_LIBRARIES="$DYLIB" examples/inline_hook_far/app)
          echo "$OUT"
          [[ "$OUT" == *"target_add(6, 7) = 42"* ]]

          cc -O0 -fno-inline examples/inline_hook_signal/target.c -o examples/inline_hook_signal/app
          DYLIB="$PWD/target/aarch64-apple-darwin/debug/examples/libinline_hook_signal.dylib"
          OUT=$(DYLD_INSERT_LIBRARIES="$DYLIB" examples/inline_hook_signal/app)
          echo "$OUT"
          [[ "$OUT" == *"target_add(6, 7) = 42"* ]]

          cc -O0 -fno-inline examples/patchcode_add_to_mul/target.c -o examples/patchcode_add_to_mul/app
          DYLIB="$PWD/target/aarch64-apple-darwin/debug/examples/libpatchcode_add_to_mul.dylib"
          OUT=$(DYLD_INSERT_LIBRARIES="$DYLIB" examples/patchcode_add_to_mul/app)
          echo "$OUT"
          [[ "$OUT" == *"calc(6, 7) = 42"* ]]

          cc -O0 -fno-inline examples/patch_asm_add_to_mul/target.c -o examples/patch_asm_add_to_mul/app
          DYLIB="$PWD/target/aarch64-apple-darwin/debug/examples/libpatch_asm_add_to_mul.dylib"
          OUT=$(DYLD_INSERT_LIBRARIES="$DYLIB" examples/patch_asm_add_to_mul/app)
          echo "$OUT"
          [[ "$OUT" == *"calc(6, 7) = 42"* ]]

  rust-macos-x86_64:
    runs-on: macos-15-intel

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Rust
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: x86_64-apple-darwin
          components: clippy

      - name: Setup Rust cache
        uses: Swatinem/rust-cache@v2

      - name: Cargo check
        run: cargo check --all-targets --target x86_64-apple-darwin

      - name: Cargo test
        run: cargo test --doc --target x86_64-apple-darwin

      - name: Cargo clippy
        run: cargo clippy --all-targets --target x86_64-apple-darwin -- -D warnings

      - name: Build six base examples (macOS x86_64)
        run: |
          cargo build --example instrument_with_original --target x86_64-apple-darwin
          cargo build --example instrument_no_original --target x86_64-apple-darwin
          cargo build --example instrument_unhook_restore --target x86_64-apple-darwin
          cargo build --example inline_hook_far --target x86_64-apple-darwin
          cargo build --example inline_hook_signal --target x86_64-apple-darwin
          cargo build --example patchcode_add_to_mul --target x86_64-apple-darwin

      - name: Run macOS x86_64 base example smoke tests
        shell: bash
        run: |
          set -euo pipefail

          cc -O0 -fno-inline examples/instrument_with_original/target.c -o examples/instrument_with_original/app
          DYLIB="$PWD/target/x86_64-apple-darwin/debug/examples/libinstrument_with_original.dylib"
          OUT=$(DYLD_INSERT_LIBRARIES="$DYLIB" examples/instrument_with_original/app)
          echo "$OUT"
          [[ "$OUT" == *"calc(1, 2) = 42"* ]]

          cc -O0 -fno-inline examples/instrument_no_original/target.c -o examples/instrument_no_original/app
          DYLIB="$PWD/target/x86_64-apple-darwin/debug/examples/libinstrument_no_original.dylib"
          OUT=$(DYLD_INSERT_LIBRARIES="$DYLIB" examples/instrument_no_original/app)
          echo "$OUT"
          [[ "$OUT" == *"calc(4, 5) = 99"* ]]

          cc -O0 -fno-inline examples/instrument_unhook_restore/target.c -o examples/instrument_unhook_restore/app
          DYLIB="$PWD/target/x86_64-apple-darwin/debug/examples/libinstrument_unhook_restore.dylib"
          OUT=$(DYLD_INSERT_LIBRARIES="$DYLIB" examples/instrument_unhook_restore/app)
          echo "$OUT"
          [[ "$OUT" == *"hooked_calc(3, 4) = 123"* ]]
          [[ "$OUT" == *"calc(3, 4) = 7"* ]]

          cc -O0 -fno-inline examples/inline_hook_far/target.c -o examples/inline_hook_far/app
          DYLIB="$PWD/target/x86_64-apple-darwin/debug/examples/libinline_hook_far.dylib"
          OUT=$(DYLD_INSERT_LIBRARIES="$DYLIB" examples/inline_hook_far/app)
          echo "$OUT"
          [[ "$OUT" == *"target_add(6, 7) = 42"* ]]

          cc -O0 -fno-inline examples/inline_hook_signal/target.c -o examples/inline_hook_signal/app
          DYLIB="$PWD/target/x86_64-apple-darwin/debug/examples/libinline_hook_signal.dylib"
          OUT=$(DYLD_INSERT_LIBRARIES="$DYLIB" examples/inline_hook_signal/app)
          echo "$OUT"
          [[ "$OUT" == *"target_add(6, 7) = 42"* ]]

          cc -O0 -fno-inline examples/patchcode_add_to_mul/target.c -o examples/patchcode_add_to_mul/app
          DYLIB="$PWD/target/x86_64-apple-darwin/debug/examples/libpatchcode_add_to_mul.dylib"
          OUT=$(DYLD_INSERT_LIBRARIES="$DYLIB" examples/patchcode_add_to_mul/app)
          echo "$OUT"
          [[ "$OUT" == *"calc(6, 7) = 42"* ]]

  rust-linux-x86_64:
    runs-on: ubuntu-24.04

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Rust
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: x86_64-unknown-linux-gnu
          components: rustfmt, clippy

      - name: Setup CMake 3.x (keystone build compatibility)
        uses: jwlawson/actions-setup-cmake@v2
        with:
          cmake-version: '3.31.6'

      - name: Setup Rust cache
        uses: Swatinem/rust-cache@v2

      - name: Cargo check
        run: cargo check --all-targets --target x86_64-unknown-linux-gnu

      - name: Cargo test
        run: cargo test --doc --target x86_64-unknown-linux-gnu

      - name: Cargo clippy
        run: cargo clippy --all-targets --target x86_64-unknown-linux-gnu -- -D warnings

      - name: Build all examples (Linux x86_64, patch_asm enabled)
        run: cargo build --examples --features patch_asm --target x86_64-unknown-linux-gnu

      - name: Run Linux x86_64 example smoke tests
        shell: bash
        run: |
          set -euo pipefail

          cc -O0 -fno-inline -rdynamic examples/instrument_with_original/target.c -o examples/instrument_with_original/app
          SO="$PWD/target/x86_64-unknown-linux-gnu/debug/examples/libinstrument_with_original.so"
          OUT=$(LD_PRELOAD="$SO" examples/instrument_with_original/app)
          echo "$OUT"
          [[ "$OUT" == *"calc(1, 2) = 42"* ]]

          cc -O0 -fno-inline -rdynamic examples/instrument_no_original/target.c -o examples/instrument_no_original/app
          SO="$PWD/target/x86_64-unknown-linux-gnu/debug/examples/libinstrument_no_original.so"
          OUT=$(LD_PRELOAD="$SO" examples/instrument_no_original/app)
          echo "$OUT"
          [[ "$OUT" == *"calc(4, 5) = 99"* ]]

          cc -O0 -fno-inline -rdynamic examples/instrument_unhook_restore/target.c -o examples/instrument_unhook_restore/app
          SO="$PWD/target/x86_64-unknown-linux-gnu/debug/examples/libinstrument_unhook_restore.so"
          OUT=$(LD_PRELOAD="$SO" examples/instrument_unhook_restore/app)
          echo "$OUT"
          [[ "$OUT" == *"hooked_calc(3, 4) = 123"* ]]
          [[ "$OUT" == *"calc(3, 4) = 7"* ]]

          cc -O0 -fno-inline -rdynamic examples/inline_hook_far/target.c -o examples/inline_hook_far/app
          SO="$PWD/target/x86_64-unknown-linux-gnu/debug/examples/libinline_hook_far.so"
          OUT=$(LD_PRELOAD="$SO" examples/inline_hook_far/app)
          echo "$OUT"
          [[ "$OUT" == *"target_add(6, 7) = 42"* ]]

          cc -O0 -fno-inline -rdynamic examples/inline_hook_signal/target.c -o examples/inline_hook_signal/app
          SO="$PWD/target/x86_64-unknown-linux-gnu/debug/examples/libinline_hook_signal.so"
          OUT=$(LD_PRELOAD="$SO" examples/inline_hook_signal/app)
          echo "$OUT"
          [[ "$OUT" == *"target_add(6, 7) = 42"* ]]

          cc -O0 -fno-inline -rdynamic examples/patchcode_add_to_mul/target.c -o examples/patchcode_add_to_mul/app
          SO="$PWD/target/x86_64-unknown-linux-gnu/debug/examples/libpatchcode_add_to_mul.so"
          OUT=$(LD_PRELOAD="$SO" examples/patchcode_add_to_mul/app)
          echo "$OUT"
          [[ "$OUT" == *"calc(6, 7) = 42"* ]]

          cc -O0 -fno-inline -rdynamic examples/patch_asm_add_to_mul/target.c -o examples/patch_asm_add_to_mul/app
          SO="$PWD/target/x86_64-unknown-linux-gnu/debug/examples/libpatch_asm_add_to_mul.so"
          OUT=$(LD_PRELOAD="$SO" examples/patch_asm_add_to_mul/app)
          echo "$OUT"
          [[ "$OUT" == *"calc(6, 7) = 42"* ]]

  rust-linux-aarch64:
    runs-on: ubuntu-24.04-arm

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Rust
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: aarch64-unknown-linux-gnu
          components: clippy

      - name: Setup CMake 3.x (keystone build compatibility)
        uses: jwlawson/actions-setup-cmake@v2
        with:
          cmake-version: '3.31.6'

      - name: Setup Rust cache
        uses: Swatinem/rust-cache@v2

      - name: Cargo check
        run: cargo check --all-targets --target aarch64-unknown-linux-gnu

      - name: Cargo test
        run: cargo test --doc --target aarch64-unknown-linux-gnu

      - name: Cargo clippy
        run: cargo clippy --all-targets --target aarch64-unknown-linux-gnu -- -D warnings

      - name: Build all examples (Linux aarch64, patch_asm enabled)
        run: cargo build --examples --features patch_asm --target aarch64-unknown-linux-gnu

      - name: Run Linux aarch64 example smoke tests
        shell: bash
        run: |
          set -euo pipefail

          cc -O0 -fno-inline -rdynamic examples/instrument_with_original/target.c -o examples/instrument_with_original/app
          SO="$PWD/target/aarch64-unknown-linux-gnu/debug/examples/libinstrument_with_original.so"
          OUT=$(LD_PRELOAD="$SO" examples/instrument_with_original/app)
          echo "$OUT"
          [[ "$OUT" == *"calc(1, 2) = 42"* ]]

          cc -O0 -fno-inline -rdynamic examples/instrument_no_original/target.c -o examples/instrument_no_original/app
          SO="$PWD/target/aarch64-unknown-linux-gnu/debug/examples/libinstrument_no_original.so"
          OUT=$(LD_PRELOAD="$SO" examples/instrument_no_original/app)
          echo "$OUT"
          [[ "$OUT" == *"calc(4, 5) = 99"* ]]

          cc -O0 -fno-inline -rdynamic examples/instrument_unhook_restore/target.c -o examples/instrument_unhook_restore/app
          SO="$PWD/target/aarch64-unknown-linux-gnu/debug/examples/libinstrument_unhook_restore.so"
          OUT=$(LD_PRELOAD="$SO" examples/instrument_unhook_restore/app)
          echo "$OUT"
          [[ "$OUT" == *"hooked_calc(3, 4) = 123"* ]]
          [[ "$OUT" == *"calc(3, 4) = 7"* ]]

          cc -O0 -fno-inline -rdynamic examples/instrument_adrp_no_original/target.c -o examples/instrument_adrp_no_original/app
          SO="$PWD/target/aarch64-unknown-linux-gnu/debug/examples/libinstrument_adrp_no_original.so"
          OUT=$(LD_PRELOAD="$SO" examples/instrument_adrp_no_original/app)
          echo "$OUT"
          [[ "$OUT" == *"calc(5, 7) = 42"* ]]

          cc -O0 -fno-inline -rdynamic examples/inline_hook_far/target.c -o examples/inline_hook_far/app
          SO="$PWD/target/aarch64-unknown-linux-gnu/debug/examples/libinline_hook_far.so"
          OUT=$(LD_PRELOAD="$SO" examples/inline_hook_far/app)
          echo "$OUT"
          [[ "$OUT" == *"target_add(6, 7) = 42"* ]]

          cc -O0 -fno-inline -rdynamic examples/inline_hook_signal/target.c -o examples/inline_hook_signal/app
          SO="$PWD/target/aarch64-unknown-linux-gnu/debug/examples/libinline_hook_signal.so"
          OUT=$(LD_PRELOAD="$SO" examples/inline_hook_signal/app)
          echo "$OUT"
          [[ "$OUT" == *"target_add(6, 7) = 42"* ]]

          cc -O0 -fno-inline -rdynamic examples/patchcode_add_to_mul/target.c -o examples/patchcode_add_to_mul/app
          SO="$PWD/target/aarch64-unknown-linux-gnu/debug/examples/libpatchcode_add_to_mul.so"
          OUT=$(LD_PRELOAD="$SO" examples/patchcode_add_to_mul/app)
          echo "$OUT"
          [[ "$OUT" == *"calc(6, 7) = 42"* ]]

          cc -O0 -fno-inline -rdynamic examples/patch_asm_add_to_mul/target.c -o examples/patch_asm_add_to_mul/app
          SO="$PWD/target/aarch64-unknown-linux-gnu/debug/examples/libpatch_asm_add_to_mul.so"
          OUT=$(LD_PRELOAD="$SO" examples/patch_asm_add_to_mul/app)
          echo "$OUT"
          [[ "$OUT" == *"calc(6, 7) = 42"* ]]

  rust-ios-aarch64:
    runs-on: macos-14

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Rust
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: aarch64-apple-ios
          components: clippy

      - name: Setup CMake 3.x (keystone build compatibility)
        uses: jwlawson/actions-setup-cmake@v2
        with:
          cmake-version: '3.31.6'

      - name: Setup Rust cache
        uses: Swatinem/rust-cache@v2

      - name: Cargo check
        run: cargo check --all-targets --target aarch64-apple-ios

      - name: Cargo check tests
        run: cargo check --tests --target aarch64-apple-ios

      - name: Cargo clippy
        run: cargo clippy --all-targets --target aarch64-apple-ios -- -D warnings

      - name: Build all examples (iOS aarch64)
        run: cargo build --examples --target aarch64-apple-ios


  rust-android-aarch64:
    runs-on: ubuntu-24.04

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Rust
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: aarch64-linux-android
          components: clippy

      - name: Setup CMake 3.x (keystone build compatibility)
        uses: jwlawson/actions-setup-cmake@v2
        with:
          cmake-version: '3.31.6'

      - name: Setup Rust cache
        uses: Swatinem/rust-cache@v2

      - name: Setup Android NDK
        uses: nttld/setup-ndk@v1
        with:
          ndk-version: r26d

      - name: Configure Android linker
        shell: bash
        run: |
          set -euo pipefail
          echo "CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android34-clang" >> "$GITHUB_ENV"

      - name: Cargo check
        run: cargo check --all-targets --target aarch64-linux-android

      - name: Cargo check tests
        run: cargo check --tests --target aarch64-linux-android

      - name: Cargo clippy
        run: cargo clippy --all-targets --target aarch64-linux-android -- -D warnings

      - name: Build all examples (Android aarch64)
        run: cargo build --examples --target aarch64-linux-android
