name: CI

on:
  push:
  pull_request:
  workflow_dispatch:
  schedule: [cron: "40 1 * * *"]

permissions:
  contents: read

env:
  RUSTFLAGS: -Dwarnings

jobs:
  pre_ci:
    uses: dtolnay/.github/.github/workflows/pre_ci.yml@master

  test:
    name: Rust ${{matrix.rust}}
    needs: pre_ci
    if: needs.pre_ci.outputs.continue
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        rust: [1.80.0, stable, beta]
    timeout-minutes: 45
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@master
        with:
          toolchain: ${{matrix.rust}}
          components: rust-src
      - run: cargo test
      - run: cargo test --no-default-features
      - run: cargo test --features span-locations
      - name: RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo test
        run: cargo test
        env:
          RUSTFLAGS: --cfg procmacro2_semver_exempt ${{env.RUSTFLAGS}}
      - name: RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo test --no-default-features
        run: cargo test --no-default-features
        env:
          RUSTFLAGS: --cfg procmacro2_semver_exempt ${{env.RUSTFLAGS}}

  nightly:
    name: Rust nightly
    needs: pre_ci
    if: needs.pre_ci.outputs.continue
    runs-on: ubuntu-latest
    timeout-minutes: 45
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@nightly
        with:
          components: rust-src
      - name: Enable type layout randomization
        run: echo RUSTFLAGS=${RUSTFLAGS}\ -Zrandomize-layout\ --cfg=randomize_layout >> $GITHUB_ENV
      - run: cargo check
        env:
          RUSTFLAGS: --cfg procmacro2_nightly_testing ${{env.RUSTFLAGS}}
      - run: cargo test
      - run: cargo test --no-default-features
      - run: cargo test --no-default-features --test features -- --ignored make_sure_no_proc_macro # run the ignored test to make sure the `proc-macro` feature is disabled
      - run: cargo test --features span-locations
      - run: cargo test --manifest-path tests/ui/Cargo.toml
      - name: RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo test
        run: cargo test
        env:
          RUSTFLAGS: --cfg procmacro2_semver_exempt ${{env.RUSTFLAGS}}
      - name: RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo test --no-default-features
        run: cargo test --no-default-features
        env:
          RUSTFLAGS: --cfg procmacro2_semver_exempt ${{env.RUSTFLAGS}}
      - name: RUSTFLAGS='-Z allow-features=' cargo test
        run: cargo test
        env:
          RUSTFLAGS: -Z allow-features= --cfg procmacro2_backtrace ${{env.RUSTFLAGS}}
      - uses: actions/upload-artifact@v6
        if: always()
        with:
          name: Cargo.lock
          path: Cargo.lock
        continue-on-error: true

  layout:
    name: Layout
    needs: pre_ci
    if: needs.pre_ci.outputs.continue
    runs-on: ubuntu-latest
    timeout-minutes: 45
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@nightly
        with:
          components: rust-src
      - run: cargo test --test test_size
      - run: cargo test --test test_size --features span-locations
      - run: cargo test --test test_size --no-default-features
      - run: cargo test --test test_size --no-default-features --features span-locations

  msrv:
    name: Rust 1.68.0
    needs: pre_ci
    if: needs.pre_ci.outputs.continue
    runs-on: ubuntu-latest
    timeout-minutes: 45
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@1.68.0
        with:
          components: rust-src
      - run: cargo check
      - run: cargo check --no-default-features
      - run: cargo check --features span-locations
      - name: RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo check
        run: cargo check
        env:
          RUSTFLAGS: --cfg procmacro2_semver_exempt ${{env.RUSTFLAGS}}
      - name: RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo check --no-default-features
        run: cargo check --no-default-features
        env:
          RUSTFLAGS: --cfg procmacro2_semver_exempt ${{env.RUSTFLAGS}}

  minimal:
    name: Minimal versions
    needs: pre_ci
    if: needs.pre_ci.outputs.continue
    runs-on: ubuntu-latest
    timeout-minutes: 45
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@nightly
      - run: cargo generate-lockfile -Z minimal-versions
      - run: cargo check --locked

  webassembly:
    name: WebAssembly
    needs: pre_ci
    if: needs.pre_ci.outputs.continue
    runs-on: ubuntu-latest
    timeout-minutes: 45
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@nightly
        with:
          target: wasm32-unknown-unknown
          components: rust-src
      - name: Ignore WebAssembly linker warning
        run: echo RUSTFLAGS=${RUSTFLAGS}\ -Alinker_messages >> $GITHUB_ENV
      - run: cargo test --target wasm32-unknown-unknown --no-run

  fuzz:
    name: Fuzz
    needs: pre_ci
    if: needs.pre_ci.outputs.continue
    runs-on: ubuntu-latest
    timeout-minutes: 45
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@nightly
        with:
          components: rust-src
      - uses: dtolnay/install@cargo-fuzz
      - run: cargo fuzz check
      - run: cargo check --no-default-features --features afl
        working-directory: fuzz
      - uses: dtolnay/install@honggfuzz
      - name: Run apt install binutils-dev libunwind-dev
        run: |
          sudo sed -i 's/^update_initramfs=yes$/update_initramfs=no/' /etc/initramfs-tools/update-initramfs.conf
          sudo rm -f /var/lib/man-db/auto-update
          sudo apt-get update
          sudo apt-get install binutils-dev libunwind-dev
      - run: cargo hfuzz build --no-default-features --features honggfuzz
        working-directory: fuzz

  doc:
    name: Documentation
    needs: pre_ci
    if: needs.pre_ci.outputs.continue
    runs-on: ubuntu-latest
    timeout-minutes: 45
    env:
      RUSTDOCFLAGS: -Dwarnings
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@nightly
        with:
          components: rust-src
      - uses: dtolnay/install@cargo-docs-rs
      - run: cargo docs-rs

  clippy:
    name: Clippy
    runs-on: ubuntu-latest
    if: github.event_name != 'pull_request'
    timeout-minutes: 45
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@nightly
        with:
          components: clippy, rust-src
      - run: cargo clippy --tests -- -Dclippy::all -Dclippy::pedantic
      - run: cargo clippy --tests --all-features -- -Dclippy::all -Dclippy::pedantic

  miri:
    name: Miri
    needs: pre_ci
    if: needs.pre_ci.outputs.continue
    runs-on: ubuntu-latest
    timeout-minutes: 45
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@miri
      - run: cargo miri setup
      - run: cargo miri test
        env:
          MIRIFLAGS: -Zmiri-strict-provenance

  outdated:
    name: Outdated
    runs-on: ubuntu-latest
    if: github.event_name != 'pull_request'
    timeout-minutes: 45
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@stable
      - uses: dtolnay/install@cargo-outdated
      - run: cargo outdated --workspace --exit-code 1
      - run: cargo outdated --manifest-path fuzz/Cargo.toml --exit-code 1
