name: CI

on:
  pull_request:
  push:
    branches: [master]

jobs:
  fmt:
    name: Tidy Code
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v6
    - uses: hecrj/setup-rust-action@v2
      with:
        rust-version: stable
        components: rustfmt
    - name: Check Formatting
      run: cargo +stable fmt --all -- --check
    - uses: taiki-e/install-action@v2
      with:
        tool: typos-cli
    - name: Check Formatting
      run: cargo fmt --all -- --check
    - name: Run Typos
      run: typos

  msrv:
    name: MSRV
    needs: fmt
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        include:
        # Android
        - target: aarch64-linux-android

        # CoreGraphics
        - target: aarch64-apple-darwin
        - target: x86_64-apple-ios

        # Orbital (doesn't follow MSRV)
        # - target: x86_64-unknown-redox

        # Wayland, KMS/DRM, X11
        - target: i686-unknown-linux-gnu
        - target: x86_64-unknown-linux-gnu
        - target: x86_64-unknown-linux-gnu
          features: "x11,x11-dlopen"
        - target: x86_64-unknown-linux-gnu
          features: "wayland,wayland-dlopen"
        - target: x86_64-unknown-linux-gnu
          features: "kms"
        - target: x86_64-unknown-freebsd
        - target: x86_64-unknown-netbsd
          features: "x11,x11-dlopen,wayland,wayland-dlopen"

        # Web
        - target: wasm32-unknown-unknown

        # Win32
        - target: x86_64-pc-windows-msvc
        - target: x86_64-pc-windows-gnu

    steps:
    - uses: actions/checkout@v6
    - uses: hecrj/setup-rust-action@v2
      with:
        rust-version: '1.71.1'
        targets: ${{ matrix.target }}

    - name: Use minimal dependency versions
      # By downgrading all our dependency versions, we ensure that our minimum
      # version bounds are actually adequate (i.e. users can build `softbuffer`
      # with minimal versions themselves) and opt-out of any unexpected MSRV
      # bumps in semver-compatible releases of downstream crates.
      #
      # RUSTC_BOOTSTRAP=1 is kind of a hack, but it's cumbersome and slow to
      # install the nightly toolchain.
      run: RUSTC_BOOTSTRAP=1 cargo -Zminimal-versions generate-lockfile

    - name: Check that crate compiles
      run: cargo check --verbose --target ${{ matrix.target }} ${{ matrix.features && '--no-default-features --features' }} ${{ matrix.features }}

  tests:
    name: Tests
    needs: fmt
    strategy:
      fail-fast: false
      matrix:
        rust_version: [stable, nightly]
        platform:
          - { target: x86_64-pc-windows-msvc,   os: windows-latest,  }
          - { target: i686-pc-windows-msvc,     os: windows-latest,  }
          # TODO: wait for https://github.com/microsoft/windows-rs/issues/2614#issuecomment-1684152597
          #       to be resolved before re-enabling these
          # - { target: x86_64-pc-windows-gnu,    os: windows-latest, host: -x86_64-pc-windows-gnu }
          # - { target: i686-pc-windows-gnu,      os: windows-latest, host: -i686-pc-windows-gnu }
          - { target: i686-unknown-linux-gnu,   os: ubuntu-latest,   }
          - { target: x86_64-unknown-linux-gnu, os: ubuntu-latest,   }
          - { target: x86_64-unknown-linux-gnu, os: ubuntu-latest, options: --no-default-features, features: "x11,x11-dlopen" }
          - { target: x86_64-unknown-linux-gnu, os: ubuntu-latest, options: --no-default-features, features: "wayland,wayland-dlopen" }
          - { target: x86_64-unknown-linux-gnu, os: ubuntu-latest, options: --no-default-features, features: "kms" }
          - { target: x86_64-unknown-redox,     os: ubuntu-latest,   }
          - { target: x86_64-unknown-freebsd,   os: ubuntu-latest,   }
          - { target: x86_64-unknown-netbsd,    os: ubuntu-latest, options: --no-default-features, features: "x11,x11-dlopen,wayland,wayland-dlopen"  }
          - { target: aarch64-apple-darwin,     os: macos-latest,    }
          - { target: wasm32-unknown-unknown,   os: ubuntu-latest,   }
        include:
          - rust_version: nightly
            platform: { target: wasm32-unknown-unknown, os: ubuntu-latest, options: "-Zbuild-std=panic_abort,std", rustflags: "-Ctarget-feature=+atomics,+bulk-memory" }
          # Mac Catalyst is only Tier 2 since Rust 1.81
          - rust_version: 'nightly'
            platform: { target: aarch64-apple-ios-macabi, os: macos-latest }

    env:
      RUST_BACKTRACE: 1
      CARGO_INCREMENTAL: 0
      RUSTFLAGS: "-C debuginfo=0 --deny warnings ${{ matrix.platform.rustflags }}"
      # Disable doc tests on Rust 1.83, since some path handling regressed there.
      # This has been fixed in Rust 1.84 beta.
      # https://github.com/rust-lang/rust/issues/132203
      OPTIONS: ${{ matrix.platform.options }} ${{ matrix.rust_version == 'stable' && '--lib' || '' }}
      FEATURES: ${{ format(',{0}', matrix.platform.features ) }}
      CMD: ${{ matrix.platform.cmd }}
      RUSTDOCFLAGS: -Dwarnings

    runs-on: ${{ matrix.platform.os }}
    steps:
    - uses: actions/checkout@v6

    - uses: taiki-e/install-action@v2
      if: matrix.platform.target == 'wasm32-unknown-unknown'
      with:
        tool: wasm-bindgen-cli

    - uses: hecrj/setup-rust-action@v2
      with:
        rust-version: ${{ matrix.rust_version }}${{ matrix.platform.host }}
        targets: ${{ matrix.platform.target }}
        components: clippy, rust-src

    - name: Install libwayland
      if: (matrix.platform.os == 'ubuntu-latest')
      run: sudo apt-get update && sudo apt-get install libwayland-dev

    - name: Install GCC Multilib
      if: (matrix.platform.os == 'ubuntu-latest') && contains(matrix.platform.target, 'i686')
      run: sudo apt-get install gcc-multilib

    - name: Build crate
      shell: bash
      run: cargo $CMD build --verbose --target ${{ matrix.platform.target }} $OPTIONS --features $FEATURES

    - name: Build tests
      shell: bash
      if: >
        !((matrix.platform.os == 'ubuntu-latest') && contains(matrix.platform.target, 'i686')) &&
        !contains(matrix.platform.target, 'redox') &&
        !contains(matrix.platform.target, 'freebsd') &&
        !contains(matrix.platform.target, 'netbsd')
      run: cargo $CMD test --no-run --verbose --target ${{ matrix.platform.target }} $OPTIONS --features $FEATURES

    - name: Run tests
      shell: bash
      if: >
        !((matrix.platform.os == 'ubuntu-latest') && contains(matrix.platform.target, 'i686')) &&
        !contains(matrix.platform.target, 'redox') &&
        !contains(matrix.platform.target, 'freebsd') &&
        !contains(matrix.platform.target, 'netbsd') &&
        !contains(matrix.platform.target, 'linux')
      run: cargo $CMD test --verbose --target ${{ matrix.platform.target }} $OPTIONS --features $FEATURES

    # TODO: We should also be using Wayland for testing here.
    - name: Run tests using Xvfb
      shell: bash
      if: >
        !((matrix.platform.os == 'ubuntu-latest') && contains(matrix.platform.target, 'i686')) &&
        !contains(matrix.platform.target, 'redox') &&
        !contains(matrix.platform.target, 'freebsd') &&
        !contains(matrix.platform.target, 'netbsd') &&
        contains(matrix.platform.target, 'linux') &&
        !contains(matrix.platform.options, '--no-default-features') &&
        !contains(matrix.platform.features, 'wayland')
      run: xvfb-run cargo $CMD test --verbose --target ${{ matrix.platform.target }} $OPTIONS --features $FEATURES

    - name: Lint with clippy
      shell: bash
      if: >
        (matrix.rust_version == 'stable') &&
        !contains(matrix.platform.options, '--no-default-features') &&
        !((matrix.platform.os == 'ubuntu-latest') && contains(matrix.platform.target, 'i686')) &&
        !contains(matrix.platform.target, 'redox') &&
        !contains(matrix.platform.target, 'freebsd') &&
        !contains(matrix.platform.target, 'netbsd')
      run: cargo clippy --all-targets --target ${{ matrix.platform.target }} $OPTIONS --features $FEATURES -- -Dwarnings

    - name: Lint with rustdoc
      shell: bash
      if: >
        (matrix.rust_version == 'stable') &&
        !contains(matrix.platform.options, '--no-default-features') &&
        !((matrix.platform.os == 'ubuntu-latest') && contains(matrix.platform.target, 'i686')) &&
        !contains(matrix.platform.target, 'redox') &&
        !contains(matrix.platform.target, 'freebsd') &&
        !contains(matrix.platform.target, 'netbsd')
      run: cargo doc --no-deps --target ${{ matrix.platform.target }} $OPTIONS --features $FEATURES --document-private-items