surelock 0.1.0

Deadlock-free locks for Rust with compile time guarantees, incremental locks, and atomic lock sets.
Documentation
{
  description = "surelock — no_std deadlock-free locks for Rust";

  inputs = {
    nixpkgs.url = "nixpkgs/nixos-25.11";

    command-utils.url = "git+https://codeberg.org/expede/nix-command-utils";
    flake-utils.url = "github:numtide/flake-utils";

    rust-overlay = {
      url = "github:oxalica/rust-overlay";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = {
    self,
    flake-utils,
    nixpkgs,
    rust-overlay,
    command-utils,
  } @ inputs:
    flake-utils.lib.eachDefaultSystem (
      system: let
        overlays = [
          (import rust-overlay)
        ];

        pkgs = import nixpkgs {
          inherit system overlays;
        };

        rustVersion = "1.90.0";

        rust-toolchain = (pkgs.rust-bin.stable.${rustVersion}.default.override {
          extensions = [
            "cargo"
            "clippy"
            "llvm-tools-preview"
            "rust-src"
            "rust-std"
            "rustfmt"
          ];

          targets = [
            "aarch64-apple-darwin"
            "x86_64-apple-darwin"

            "x86_64-unknown-linux-musl"
            "aarch64-unknown-linux-musl"

            "wasm32-unknown-unknown"
            "thumbv6m-none-eabi"
          ];
        }).overrideAttrs (old: {
          meta = (old.meta or {}) // {mainProgram = "cargo";};
        });

        # Nightly rustfmt for unstable formatting options (imports_granularity, etc.)
        # We need a combined nightly toolchain (rustc + rustfmt) because rustfmt
        # links against librustc_driver, which lives in the rustc component.
        # On macOS, symlinks break @rpath resolution, so we wrap the binary
        # with DYLD_LIBRARY_PATH pointing to the combined toolchain's lib/.
        nightly-rustfmt-unwrapped = pkgs.rust-bin.nightly.latest.minimal.override {
          extensions = ["rustfmt"];
        };

        nightly-rustfmt = pkgs.writeShellScriptBin "rustfmt" ''
          export DYLD_LIBRARY_PATH="${nightly-rustfmt-unwrapped}/lib''${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}"
          export LD_LIBRARY_PATH="${nightly-rustfmt-unwrapped}/lib''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
          exec "${nightly-rustfmt-unwrapped}/bin/rustfmt" "$@"
        '';

        format-pkgs = with pkgs; [
          alejandra
          nixpkgs-fmt
          taplo
        ];

        cargo-installs = with pkgs; [
          cargo-criterion
          cargo-deny
          cargo-expand
          cargo-hack
          cargo-nextest
          cargo-semver-checks
          cargo-sort
          cargo-watch
          typos
        ];

        # Built-in command modules from nix-command-utils
        rust = command-utils.rust.${system};
        cmd = command-utils.cmd.${system};
        asModule = command-utils.asModule.${system};

        # Project-specific commands
        projectCommands = import ./nix/commands.nix {
          inherit pkgs system cmd;
        };

        command_menu = command-utils.commands.${system} [
          (rust.build {cargo = rust-toolchain;})
          (rust.test {
            cargo = rust-toolchain;
            cargo-watch = pkgs.cargo-watch;
          })
          (rust.lint {cargo = rust-toolchain;})
          (rust.fmt {cargo = rust-toolchain;})
          (rust.doc {cargo = rust-toolchain;})
          (rust.bench {
            cargo = rust-toolchain;
            cargo-criterion = pkgs.cargo-criterion;
            xdg-open = pkgs.xdg-utils;
          })
          (rust.watch {cargo-watch = pkgs.cargo-watch;})
          (rust.audit {cargo-audit = pkgs.cargo-audit;})
          (rust.semver {cargo-semver-checks = pkgs.cargo-semver-checks;})
          (rust.ci {cargo = rust-toolchain;})

          # Project-specific commands
          (asModule projectCommands)
        ];

        # Minimal CI toolchain — no llvm-tools, no rust-src, fewer targets
        ci-rust-toolchain = (pkgs.rust-bin.stable.${rustVersion}.default.override {
          extensions = [
            "cargo"
            "clippy"
            "rustfmt"
          ];

          targets = [
            "wasm32-unknown-unknown"
            "thumbv6m-none-eabi"
          ];
        }).overrideAttrs (old: {
          meta = (old.meta or {}) // {mainProgram = "cargo";};
        });

        # Stub so tools that probe for rustup (e.g. cargo-semver-checks)
        # silently succeed instead of failing with "No such file or directory".
        rustup-shim = pkgs.writeShellScriptBin "rustup" ''
          if [ "$1" = "--version" ]; then
            echo "rustup-nix-shim"
          elif [ "$1" = "toolchain" ]; then
            exit 0
          elif [ "$1" = "which" ]; then
            command -v "$2" 2>/dev/null || echo "$2"
          else
            exit 0
          fi
        '';

        ci-cargo-installs = with pkgs; [
          cargo-deny
          cargo-hack
          cargo-semver-checks
          typos
        ];
      in rec {
        devShells.default = pkgs.mkShell {
          name = "surelock_shell";

          nativeBuildInputs =
            [
              command_menu
              rust-toolchain
              nightly-rustfmt

              pkgs.rust-analyzer
            ]
            ++ format-pkgs
            ++ cargo-installs
            ++ pkgs.lib.optionals pkgs.stdenv.isLinux [
              pkgs.clang
              pkgs.llvmPackages.libclang
            ];

          shellHook = ''
            unset SOURCE_DATE_EPOCH
            export WORKSPACE_ROOT="$(pwd)"
            export RUSTFMT="${nightly-rustfmt}/bin/rustfmt"
            menu
          '';
        };

        devShells.ci = pkgs.mkShell {
          name = "surelock_ci";

          nativeBuildInputs =
            [
              ci-rust-toolchain
              rustup-shim
            ]
            ++ ci-cargo-installs;
        };

        formatter = pkgs.alejandra;
      }
    );
}