Init rust project structure

This commit is contained in:
2026-02-18 07:43:30 -05:00
commit 409ee36827
12 changed files with 1413 additions and 0 deletions

513
.devenv.flake.nix Normal file
View File

@@ -0,0 +1,513 @@
{
inputs =
let
vars = {
version = "1.11.2";
system = "x86_64-linux";
devenv_root = "/home/patrick/open-cut-list";
project_input_ref = "path:/home/patrick/open-cut-list";
devenv_dotfile = "/home/patrick/open-cut-list/.devenv";
devenv_dotfile_path = ./.devenv;
devenv_tmpdir = "/run/user/1000";
devenv_runtime = "/run/user/1000/devenv-eaf4f1b";
devenv_istesting = false;
devenv_direnvrc_latest_version = 1;
container_name = null;
active_profiles = [
];
hostname = "nixology";
username = "patrick";
git_root = "/home/patrick/open-cut-list";
secretspec = null;
};
in
{
git-hooks.url = "github:cachix/git-hooks.nix";
git-hooks.inputs.nixpkgs.follows = "nixpkgs";
pre-commit-hooks.follows = "git-hooks";
nixpkgs.url = "github:cachix/devenv-nixpkgs/rolling";
devenv.url = "github:cachix/devenv?dir=src/modules";
}
// (
if builtins.pathExists (vars.devenv_dotfile_path + "/flake.json") then
builtins.fromJSON (builtins.readFile (vars.devenv_dotfile_path + "/flake.json"))
else
{ }
);
outputs =
{ nixpkgs, ... }@inputs:
let
vars = {
version = "1.11.2";
system = "x86_64-linux";
devenv_root = "/home/patrick/open-cut-list";
project_input_ref = "path:/home/patrick/open-cut-list";
devenv_dotfile = "/home/patrick/open-cut-list/.devenv";
devenv_dotfile_path = ./.devenv;
devenv_tmpdir = "/run/user/1000";
devenv_runtime = "/run/user/1000/devenv-eaf4f1b";
devenv_istesting = false;
devenv_direnvrc_latest_version = 1;
container_name = null;
active_profiles = [
];
hostname = "nixology";
username = "patrick";
git_root = "/home/patrick/open-cut-list";
secretspec = null;
};
devenv =
if builtins.pathExists (vars.devenv_dotfile_path + "/devenv.json") then
builtins.fromJSON (builtins.readFile (vars.devenv_dotfile_path + "/devenv.json"))
else
{ };
systems = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
# Function to create devenv configuration for a specific system with profiles support
mkDevenvForSystem =
targetSystem:
let
getOverlays =
inputName: inputAttrs:
map (
overlay:
let
input =
inputs.${inputName} or (throw "No such input `${inputName}` while trying to configure overlays.");
in
input.overlays.${overlay}
or (throw "Input `${inputName}` has no overlay called `${overlay}`. Supported overlays: ${nixpkgs.lib.concatStringsSep ", " (builtins.attrNames input.overlays)}")
) inputAttrs.overlays or [ ];
overlays = nixpkgs.lib.flatten (nixpkgs.lib.mapAttrsToList getOverlays (devenv.inputs or { }));
permittedUnfreePackages =
devenv.nixpkgs.per-platform."${targetSystem}".permittedUnfreePackages
or devenv.nixpkgs.permittedUnfreePackages or [ ];
pkgs = import nixpkgs {
system = targetSystem;
config = {
allowUnfree =
devenv.nixpkgs.per-platform."${targetSystem}".allowUnfree or devenv.nixpkgs.allowUnfree
or devenv.allowUnfree or false;
allowBroken =
devenv.nixpkgs.per-platform."${targetSystem}".allowBroken or devenv.nixpkgs.allowBroken
or devenv.allowBroken or false;
cudaSupport =
devenv.nixpkgs.per-platform."${targetSystem}".cudaSupport or devenv.nixpkgs.cudaSupport or false;
cudaCapabilities =
devenv.nixpkgs.per-platform."${targetSystem}".cudaCapabilities or devenv.nixpkgs.cudaCapabilities
or [ ];
permittedInsecurePackages =
devenv.nixpkgs.per-platform."${targetSystem}".permittedInsecurePackages
or devenv.nixpkgs.permittedInsecurePackages or devenv.permittedInsecurePackages or [ ];
allowUnfreePredicate =
if (permittedUnfreePackages != [ ]) then
(pkg: builtins.elem (nixpkgs.lib.getName pkg) permittedUnfreePackages)
else
(_: false);
};
inherit overlays;
};
inherit (pkgs) lib;
importModule =
path:
if lib.hasPrefix "./" path then
if lib.hasSuffix ".nix" path then
./. + (builtins.substring 1 255 path)
else
./. + (builtins.substring 1 255 path) + "/devenv.nix"
else if lib.hasPrefix "../" path then
# For parent directory paths, concatenate with /.
# ./. refers to the directory containing this file (project root)
# So ./. + "/../shared" = <project-root>/../shared
if lib.hasSuffix ".nix" path then ./. + "/${path}" else ./. + "/${path}/devenv.nix"
else
let
paths = lib.splitString "/" path;
name = builtins.head paths;
input = inputs.${name} or (throw "Unknown input ${name}");
subpath = "/${lib.concatStringsSep "/" (builtins.tail paths)}";
devenvpath = "${input}" + subpath;
devenvdefaultpath = devenvpath + "/devenv.nix";
in
if lib.hasSuffix ".nix" devenvpath then
devenvpath
else if builtins.pathExists devenvdefaultpath then
devenvdefaultpath
else
throw (devenvdefaultpath + " file does not exist for input ${name}.");
# Phase 1: Base evaluation to extract profile definitions
baseProject = pkgs.lib.evalModules {
specialArgs = inputs // {
inherit inputs;
};
modules = [
(
{ config, ... }:
{
_module.args.pkgs = pkgs.appendOverlays (config.overlays or [ ]);
}
)
(inputs.devenv.modules + /top-level.nix)
(
{ options, ... }:
{
config.devenv = lib.mkMerge [
{
cliVersion = vars.version;
root = vars.devenv_root;
dotfile = vars.devenv_dotfile;
}
(pkgs.lib.optionalAttrs (builtins.hasAttr "tmpdir" options.devenv) {
tmpdir = vars.devenv_tmpdir;
})
(pkgs.lib.optionalAttrs (builtins.hasAttr "isTesting" options.devenv) {
isTesting = vars.devenv_istesting;
})
(pkgs.lib.optionalAttrs (builtins.hasAttr "runtime" options.devenv) {
runtime = vars.devenv_runtime;
})
(pkgs.lib.optionalAttrs (builtins.hasAttr "direnvrcLatestVersion" options.devenv) {
direnvrcLatestVersion = vars.devenv_direnvrc_latest_version;
})
];
}
)
(
{ options, ... }:
{
config = lib.mkMerge [
(pkgs.lib.optionalAttrs (builtins.hasAttr "git" options) {
git.root = vars.git_root;
})
];
}
)
(pkgs.lib.optionalAttrs (vars.container_name != null) {
container.isBuilding = pkgs.lib.mkForce true;
containers.${vars.container_name}.isBuilding = true;
})
]
++ (map importModule (devenv.imports or [ ]))
++ [
(if builtins.pathExists ./devenv.nix then ./devenv.nix else { })
(devenv.devenv or { })
(if builtins.pathExists ./devenv.local.nix then ./devenv.local.nix else { })
(
if builtins.pathExists (vars.devenv_dotfile_path + "/cli-options.nix") then
import (vars.devenv_dotfile_path + "/cli-options.nix")
else
{ }
)
];
};
# Phase 2: Extract and apply profiles using extendModules with priority overrides
project =
let
# Build ordered list of profile names: hostname -> user -> manual
manualProfiles = vars.active_profiles;
currentHostname = vars.hostname;
currentUsername = vars.username;
hostnameProfiles = lib.optional (
currentHostname != ""
&& builtins.hasAttr currentHostname (baseProject.config.profiles.hostname or { })
) "hostname.${currentHostname}";
userProfiles = lib.optional (
currentUsername != "" && builtins.hasAttr currentUsername (baseProject.config.profiles.user or { })
) "user.${currentUsername}";
# Ordered list of profiles to activate
orderedProfiles = hostnameProfiles ++ userProfiles ++ manualProfiles;
# Resolve profile extends with cycle detection
resolveProfileExtends =
profileName: visited:
if builtins.elem profileName visited then
throw "Circular dependency detected in profile extends: ${lib.concatStringsSep " -> " visited} -> ${profileName}"
else
let
profile = getProfileConfig profileName;
extends = profile.extends or [ ];
newVisited = visited ++ [ profileName ];
extendedProfiles = lib.flatten (map (name: resolveProfileExtends name newVisited) extends);
in
extendedProfiles ++ [ profileName ];
# Get profile configuration by name from baseProject
getProfileConfig =
profileName:
if lib.hasPrefix "hostname." profileName then
let
name = lib.removePrefix "hostname." profileName;
in
baseProject.config.profiles.hostname.${name}
else if lib.hasPrefix "user." profileName then
let
name = lib.removePrefix "user." profileName;
in
baseProject.config.profiles.user.${name}
else
let
availableProfiles = builtins.attrNames (baseProject.config.profiles or { });
hostnameProfiles = map (n: "hostname.${n}") (
builtins.attrNames (baseProject.config.profiles.hostname or { })
);
userProfiles = map (n: "user.${n}") (builtins.attrNames (baseProject.config.profiles.user or { }));
allAvailableProfiles = availableProfiles ++ hostnameProfiles ++ userProfiles;
in
baseProject.config.profiles.${profileName}
or (throw "Profile '${profileName}' not found. Available profiles: ${lib.concatStringsSep ", " allAvailableProfiles}");
# Fold over ordered profiles to build final list with extends
expandedProfiles = lib.foldl' (
acc: profileName:
let
allProfileNames = resolveProfileExtends profileName [ ];
in
acc ++ allProfileNames
) [ ] orderedProfiles;
# Map over expanded profiles and apply priorities
allPrioritizedModules = lib.imap0 (
index: profileName:
let
# Decrement priority for each profile (lower = higher precedence)
# Start with the next lowest priority after the default priority for values (100)
profilePriority = (lib.modules.defaultOverridePriority - 1) - index;
profileConfig = getProfileConfig profileName;
# Check if an option type needs explicit override to resolve conflicts
# Only apply overrides to LEAF values (scalars), not collection types that can merge
typeNeedsOverride =
type:
if type == null then
false
else
let
typeName = type.name or type._type or "";
# True leaf types that need priority resolution when they conflict
isLeafType = builtins.elem typeName [
"str"
"int"
"bool"
"enum"
"path"
"package"
"float"
"anything"
];
in
if isLeafType then
true
else if typeName == "nullOr" then
# For nullOr, check the wrapped type recursively
let
innerType =
type.elemType
or (if type ? nestedTypes && type.nestedTypes ? elemType then type.nestedTypes.elemType else null);
in
if innerType != null then typeNeedsOverride innerType else false
else
# Everything else (collections, submodules, etc.) should merge naturally
false;
# Check if a config path needs explicit override
pathNeedsOverride =
optionPath:
let
# Try direct option first
directOption = lib.attrByPath optionPath null baseProject.options;
in
if directOption != null && lib.isOption directOption then
typeNeedsOverride directOption.type
else if optionPath != [ ] then
# Check parent for freeform type
let
parentPath = lib.init optionPath;
parentOption = lib.attrByPath parentPath null baseProject.options;
in
if parentOption != null && lib.isOption parentOption then
let
# Look for freeform type:
# 1. Standard location: type.freeformType (primary)
# 2. Nested location: type.nestedTypes.freeformType (evaluated form)
freeformType = parentOption.type.freeformType or parentOption.type.nestedTypes.freeformType or null;
elementType =
if freeformType ? elemType then
freeformType.elemType
else if freeformType ? nestedTypes && freeformType.nestedTypes ? elemType then
freeformType.nestedTypes.elemType
else
freeformType;
in
typeNeedsOverride elementType
else
false
else
false;
# Support overriding both plain attrset modules and functions
applyModuleOverride =
config:
if builtins.isFunction config then
let
wrapper = args: applyOverrideRecursive (config args) [ ];
in
lib.mirrorFunctionArgs config wrapper
else
applyOverrideRecursive config [ ];
# Apply overrides recursively based on option types
applyOverrideRecursive =
config: optionPath:
if lib.isAttrs config && config ? _type then
config # Don't touch values with existing type metadata
else if lib.isAttrs config then
lib.mapAttrs (name: value: applyOverrideRecursive value (optionPath ++ [ name ])) config
else if pathNeedsOverride optionPath then
lib.mkOverride profilePriority config
else
config;
# Apply priority overrides recursively to the deferredModule imports structure
prioritizedConfig = (
profileConfig.module
// {
imports = lib.map (
importItem:
importItem
// {
imports = lib.map (nestedImport: applyModuleOverride nestedImport) (importItem.imports or [ ]);
}
) (profileConfig.module.imports or [ ]);
}
);
in
prioritizedConfig
) expandedProfiles;
in
if allPrioritizedModules == [ ] then
baseProject
else
baseProject.extendModules { modules = allPrioritizedModules; };
config = project.config;
options = pkgs.nixosOptionsDoc {
options = builtins.removeAttrs project.options [ "_module" ];
warningsAreErrors = false;
# Unpack Nix types, e.g. literalExpression, mDoc.
transformOptions =
let
isDocType =
v:
builtins.elem v [
"literalDocBook"
"literalExpression"
"literalMD"
"mdDoc"
];
in
lib.attrsets.mapAttrs (
_: v:
if v ? _type && isDocType v._type then
v.text
else if v ? _type && v._type == "derivation" then
v.name
else
v
);
};
# Recursively search for outputs in the config.
# This is used when not building a specific output by attrpath.
build =
options: config:
lib.concatMapAttrs (
name: option:
if lib.isOption option then
let
typeName = option.type.name or "";
in
if
builtins.elem typeName [
"output"
"outputOf"
]
then
{ ${name} = config.${name}; }
else
{ }
else if builtins.isAttrs option && !lib.isDerivation option then
let
v = build option config.${name};
in
if v != { } then
{
${name} = v;
}
else
{ }
else
{ }
) options;
in
{
inherit
config
options
build
project
;
shell = config.shell;
packages = {
optionsJSON = options.optionsJSON;
# deprecated
inherit (config)
info
procfileScript
procfileEnv
procfile
;
ci = config.ciDerivation;
};
};
# Generate per-system devenv configurations
perSystem = nixpkgs.lib.genAttrs systems mkDevenvForSystem;
# Default devenv for the current system
currentSystemDevenv = perSystem.${vars.system};
in
{
devShell = nixpkgs.lib.genAttrs systems (s: perSystem.${s}.shell);
packages = nixpkgs.lib.genAttrs systems (s: perSystem.${s}.packages);
# Per-system devenv configurations
devenv = {
# Default devenv for the current system
inherit (currentSystemDevenv)
config
options
build
shell
packages
project
;
# Per-system devenv configurations
inherit perSystem;
};
# Legacy build output
build = currentSystemDevenv.build currentSystemDevenv.options currentSystemDevenv.config;
};
}

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/target
/.devenv

688
Cargo.lock generated Normal file
View File

@@ -0,0 +1,688 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "async-trait"
version = "0.1.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "atomic-waker"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "axum"
version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f"
dependencies = [
"async-trait",
"axum-core",
"bytes",
"futures-util",
"http",
"http-body",
"http-body-util",
"hyper",
"hyper-util",
"itoa",
"matchit",
"memchr",
"mime",
"percent-encoding",
"pin-project-lite",
"rustversion",
"serde",
"serde_json",
"serde_path_to_error",
"serde_urlencoded",
"sync_wrapper",
"tokio",
"tower",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "axum-core"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199"
dependencies = [
"async-trait",
"bytes",
"futures-util",
"http",
"http-body",
"http-body-util",
"mime",
"pin-project-lite",
"rustversion",
"sync_wrapper",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "bitflags"
version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
[[package]]
name = "bytes"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "core-lib"
version = "0.1.0"
[[package]]
name = "errno"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.61.2",
]
[[package]]
name = "form_urlencoded"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
dependencies = [
"percent-encoding",
]
[[package]]
name = "futures-channel"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
dependencies = [
"futures-core",
]
[[package]]
name = "futures-core"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
[[package]]
name = "futures-task"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
[[package]]
name = "futures-util"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
dependencies = [
"futures-core",
"futures-task",
"pin-project-lite",
"slab",
]
[[package]]
name = "http"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
dependencies = [
"bytes",
"itoa",
]
[[package]]
name = "http-body"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
dependencies = [
"bytes",
"http",
]
[[package]]
name = "http-body-util"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
dependencies = [
"bytes",
"futures-core",
"http",
"http-body",
"pin-project-lite",
]
[[package]]
name = "httparse"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
[[package]]
name = "httpdate"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "hyper"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11"
dependencies = [
"atomic-waker",
"bytes",
"futures-channel",
"futures-core",
"http",
"http-body",
"httparse",
"httpdate",
"itoa",
"pin-project-lite",
"pin-utils",
"smallvec",
"tokio",
]
[[package]]
name = "hyper-util"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0"
dependencies = [
"bytes",
"http",
"http-body",
"hyper",
"pin-project-lite",
"tokio",
"tower-service",
]
[[package]]
name = "itoa"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
[[package]]
name = "libc"
version = "0.2.182"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112"
[[package]]
name = "lock_api"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
dependencies = [
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "matchit"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
[[package]]
name = "memchr"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
[[package]]
name = "mime"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "mio"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
dependencies = [
"libc",
"wasi",
"windows-sys 0.61.2",
]
[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "parking_lot"
version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-link",
]
[[package]]
name = "percent-encoding"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]]
name = "pin-project-lite"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "proc-macro2"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
dependencies = [
"bitflags",
]
[[package]]
name = "rustversion"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "ryu"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
dependencies = [
"itoa",
"memchr",
"serde",
"serde_core",
"zmij",
]
[[package]]
name = "serde_path_to_error"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457"
dependencies = [
"itoa",
"serde",
"serde_core",
]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [
"form_urlencoded",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "server"
version = "0.1.0"
dependencies = [
"axum",
"core-lib",
"tokio",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
dependencies = [
"errno",
"libc",
]
[[package]]
name = "slab"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "socket2"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0"
dependencies = [
"libc",
"windows-sys 0.60.2",
]
[[package]]
name = "syn"
version = "2.0.116"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "sync_wrapper"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
[[package]]
name = "tokio"
version = "1.49.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86"
dependencies = [
"bytes",
"libc",
"mio",
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys 0.61.2",
]
[[package]]
name = "tokio-macros"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tower"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4"
dependencies = [
"futures-core",
"futures-util",
"pin-project-lite",
"sync_wrapper",
"tokio",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tower-layer"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
[[package]]
name = "tower-service"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
[[package]]
name = "tracing"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
dependencies = [
"log",
"pin-project-lite",
"tracing-core",
]
[[package]]
name = "tracing-core"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
dependencies = [
"once_cell",
]
[[package]]
name = "tui"
version = "0.1.0"
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-targets"
version = "0.53.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
dependencies = [
"windows-link",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
[[package]]
name = "windows_i686_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
[[package]]
name = "windows_i686_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]]
name = "zmij"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"

8
Cargo.toml Normal file
View File

@@ -0,0 +1,8 @@
[workspace]
members = [
"core-lib",
"server",
"tui",
]
resolver = "2"

6
core-lib/Cargo.toml Normal file
View File

@@ -0,0 +1,6 @@
[package]
name = "core-lib"
version = "0.1.0"
edition = "2024"
[dependencies]

14
core-lib/src/lib.rs Normal file
View File

@@ -0,0 +1,14 @@
pub fn add(left: u64, right: u64) -> u64 {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}

123
devenv.lock Normal file
View File

@@ -0,0 +1,123 @@
{
"nodes": {
"devenv": {
"locked": {
"dir": "src/modules",
"lastModified": 1771409465,
"owner": "cachix",
"repo": "devenv",
"rev": "f953e09075b1b3cec70e73230a38b523c606d396",
"type": "github"
},
"original": {
"dir": "src/modules",
"owner": "cachix",
"repo": "devenv",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1767039857,
"owner": "NixOS",
"repo": "flake-compat",
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "flake-compat",
"type": "github"
}
},
"git-hooks": {
"inputs": {
"flake-compat": "flake-compat",
"gitignore": "gitignore",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1770726378,
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "5eaaedde414f6eb1aea8b8525c466dc37bba95ae",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"git-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1762808025,
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "cb5e3fdca1de58ccbc3ef53de65bd372b48f567c",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"nixpkgs": {
"inputs": {
"nixpkgs-src": "nixpkgs-src"
},
"locked": {
"lastModified": 1770434727,
"owner": "cachix",
"repo": "devenv-nixpkgs",
"rev": "8430f16a39c27bdeef236f1eeb56f0b51b33d348",
"type": "github"
},
"original": {
"owner": "cachix",
"ref": "rolling",
"repo": "devenv-nixpkgs",
"type": "github"
}
},
"nixpkgs-src": {
"flake": false,
"locked": {
"lastModified": 1769922788,
"narHash": "sha256-H3AfG4ObMDTkTJYkd8cz1/RbY9LatN5Mk4UF48VuSXc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "207d15f1a6603226e1e223dc79ac29c7846da32e",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"devenv": "devenv",
"git-hooks": "git-hooks",
"nixpkgs": "nixpkgs",
"pre-commit-hooks": [
"git-hooks"
]
}
}
},
"root": "root",
"version": 7
}

13
devenv.nix Normal file
View File

@@ -0,0 +1,13 @@
{
pkgs,
lib,
config,
...
}:
{
# https://devenv.sh/languages/
languages.rust.enable = true;
# See full reference at https://devenv.sh/reference/options/
}

10
server/Cargo.toml Normal file
View File

@@ -0,0 +1,10 @@
[package]
name = "server"
version = "0.1.0"
edition = "2024"
[dependencies]
axum = "0.7"
tokio = { version = "1", features = ["full"] }
core-lib = { path = "../core-lib" }

27
server/src/main.rs Normal file
View File

@@ -0,0 +1,27 @@
use axum::{
routing::{get, post},
Router,
};
use std::net::SocketAddr;
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/health", get(health))
.route("/hello", post(hello));
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
println!("Listening on {}", addr);
let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
axum::serve(listener, app).await.unwrap();
}
async fn health() -> &'static str {
"ok"
}
async fn hello() -> &'static str {
"hello world"
}

6
tui/Cargo.toml Normal file
View File

@@ -0,0 +1,6 @@
[package]
name = "tui"
version = "0.1.0"
edition = "2024"
[dependencies]

3
tui/src/main.rs Normal file
View File

@@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}