version: '2.1'

workflows:
  version: 2
  build:
    jobs:
      - build:
          matrix:
            parameters:
              rust_img: [
                # Yes, a single-parameter axis, but means it can be referred to as a cache parameter easily without
                # duplicating the magic version number throughout this file.
                # The default rust images (not -slim or -alpine) are based on buildpack-deps. Hopefully this will
                # be easier on the CI hosts since presumably those fat lower layers will already be cached, and
                # therefore faster than a minimal, customized alpine.
                # MSRV
                'rust:1.48.0'
              ]
              # a hacky scheme to work around CircleCI's inability to deal with mutable docker tags, forcing us to
              # get a nightly or stable toolchain via rustup instead of a mutable docker tag
              toolchain_override: [
                '__msrv__', # won't add any other toolchains, just uses what's in the docker image
                '1.70.0', # minimum needed to build dev-dependencies
                'stable',
                'beta',
                'nightly'
              ]

jobs:
  build:
    parameters:
      rust_img:
        type: string
      toolchain_override:
        type: string
    docker:
      - image: << parameters.rust_img >>
    steps:
      - checkout
      - restore_cache:
          key: project-cache-v5-<< parameters.rust_img >>-<< parameters.toolchain_override >>-{{ checksum "Cargo.toml" }}
      - run:
          name: Setup toolchain
          command: |
            if [[ '<< parameters.toolchain_override >>' != '__msrv__' ]]
            then
              rustup toolchain add '<< parameters.toolchain_override >>'
              rustup default '<< parameters.toolchain_override >>'
            fi
      - run:
          name: Log rustc version
          command: rustc --version
      - run:
          name: Build main target
          # update first to select dependencies appropriate for this toolchain
          command: |
            cargo update
            cargo build
      - run:
          name: Check formatting
          command: |
            rustup component add rustfmt
            cargo fmt -- --check
      - run:
          name: Check clippy lints
          # we only care about stable clippy -- nightly clippy is a bit wild
          command: |
            if [[ '<< parameters.toolchain_override >>' == 'stable' ]]
            then
              rustup component add clippy
              cargo clippy --all-targets
            fi
      - run:
          name: Build all targets
          command: |
            if [[ '<< parameters.toolchain_override >>' != '__msrv__' ]]
            then
              cargo build --all-targets
            fi
      - run:
          name: Build without default features
          command: |
            cargo build --no-default-features
            if [[ '<< parameters.toolchain_override >>' != '__msrv__' ]]
            then
              cargo build --no-default-features --all-targets
            fi
      - run:
          name: Build with only alloc
          command: |
            cargo build --no-default-features --features alloc
            if [[ '<< parameters.toolchain_override >>' != '__msrv__' ]]
            then
              cargo build --no-default-features --features alloc --all-targets
            fi
      - run:
          name: Add arm toolchain
          command: rustup target add thumbv6m-none-eabi
      - run:
          name: Build ARM without default features (no_std)
          command: cargo build --target thumbv6m-none-eabi --no-default-features
      - run:
          name: Build ARM with only alloc feature
          command: cargo build --target thumbv6m-none-eabi --no-default-features --features alloc
      - run:
          # dev dependencies can't build on 1.48.0
          name: Run tests
          command: |
            if [[ '<< parameters.toolchain_override >>' != '__msrv__' ]]
            then
              cargo test --no-default-features
              cargo test
            fi
      - run:
          name: Build docs
          command: cargo doc --verbose
      - run:
          name: Confirm fuzzers can run
          # TERM=dumb prevents cargo fuzz list from printing with color
          environment:
            TERM: dumb
          command: |
            if [[ '<< parameters.toolchain_override >>' = 'nightly' ]]
            then
              cargo install cargo-fuzz
              cargo fuzz list | xargs -I FUZZER cargo fuzz run FUZZER -- -max_total_time=1
            fi

      - save_cache:
          key: project-cache-v5-<< parameters.rust_img >>-<< parameters.toolchain_override >>-{{ checksum "Cargo.toml" }}
          paths:
            # rust docker img doesn't use $HOME/[.cargo,.rustup]
            - /usr/local/cargo
            - /usr/local/rustup
            - ./target
