fake.modules transposition for aspect-oriented Dendritic Nix. with cross-aspect dependencies. Discussions: https://oeiuwq.zulipchat.com/join/nqp26cd4kngon6mo3ncgnuap/ dendrix.oeiuwq.com/Dendritic.html
dendritic nix aspect oriented

perf(core): Some optimizations (#40)

Now 1.16x times faster than previous main.

```
hyperfine -m 20 -w 10 -n perf "cd perf && just ci" -n main "cd main && just ci"
Benchmark 1: perf
Time (mean ± σ): 114.5 ms ± 1.7 ms [User: 77.2 ms, System: 32.3 ms]
Range (min … max): 111.7 ms … 119.3 ms 25 runs

Benchmark 2: main
Time (mean ± σ): 133.3 ms ± 1.7 ms [User: 91.7 ms, System: 36.5 ms]
Range (min … max): 130.9 ms … 137.2 ms 22 runs

Summary
perf ran
1.16 ± 0.02 times faster than main

```

authored by oeiuwq.com and committed by

GitHub 81a51a89 778d8d7c

+50 -47
+14
Justfile
··· 1 + help: 2 + just -l 3 + 4 + docs: 5 + cd docs && pnpm run dev 6 + 7 + ci test="": 8 + nix-unit --override-input target . --flake github:vic/checkmate#.tests.systems.x86_64-linux.system-agnostic.{{test}} 9 + 10 + check: 11 + nix flake check --override-input target . github:vic/checkmate 12 + 13 + fmt: 14 + nix run github:vic/checkmate#fmt --override-input target .
+4 -1
checkmate/modules/formatter.nix
··· 1 1 { 2 2 perSystem.treefmt.programs.nixf-diagnose.enable = false; 3 - perSystem.treefmt.settings.global.excludes = [ "docs/*" ]; 3 + perSystem.treefmt.settings.global.excludes = [ 4 + "docs/*" 5 + "Justfile" 6 + ]; 4 7 }
+3 -2
nix/forward.nix
··· 1 - lib: 2 1 # An utility for creating new aspect configuration classes that 3 2 # help with separation of concerns. 4 3 # ··· 39 38 # 40 39 # See checkmate/modules/tests/forward.nix for working example. 41 40 # 41 + lib: 42 42 { 43 43 each, 44 44 fromClass, ··· 47 47 fromAspect, 48 48 }: 49 49 let 50 + resolve = import ./resolve.nix lib; 50 51 include = 51 52 item: 52 53 let ··· 54 55 into = intoClass item; 55 56 path = intoPath item; 56 57 aspect = fromAspect item; 57 - module = aspect.resolve { class = from; }; 58 + module = resolve from [ ] aspect; 58 59 config = lib.setAttrByPath path ( 59 60 { ... }: 60 61 {
+2 -13
nix/lib.nix
··· 1 - # Public API entry point for flake-aspects library 2 - # Exports: types, transpose, aspects, new, new-scope 3 1 lib: 4 2 let 5 - # Type system: aspectsType, aspectSubmodule, providerType 6 3 types = import ./types.nix lib; 7 - 8 - # Generic transposition utility: parameterized by emit function 4 + resolve = import ./resolve.nix lib; 9 5 transpose = 10 6 { 11 7 emit ? lib.singleton, 12 8 }: 13 9 import ./default.nix { inherit lib emit; }; 14 - 15 - # Aspect transposition with resolution 16 10 aspects = import ./aspects.nix lib; 17 - 18 - # Dynamic class forwarding into submodules 19 11 forward = import ./forward.nix lib; 20 - 21 - # Low-level scope factory: parameterized by callback 22 12 new = import ./new.nix lib; 23 - 24 - # High-level named scope factory 25 13 new-scope = import ./new-scope.nix new; 26 14 in 27 15 { ··· 32 20 new 33 21 new-scope 34 22 forward 23 + resolve 35 24 ; 36 25 }
+16 -8
nix/resolve.nix
··· 1 - # Core aspect resolution algorithm 2 - # Resolves aspect definitions into nixpkgs modules with dependency resolution 3 - 4 1 lib: 5 2 let 6 - # Process a single provider: invoke with context and resolve 7 3 include = 8 4 class: aspect-chain: provider: 9 5 let 10 - provided = provider { inherit aspect-chain class; }; 6 + provided = if lib.isFunction provider then provider { inherit aspect-chain class; } else provider; 11 7 in 12 - resolve class aspect-chain provided; 8 + inner class aspect-chain provided; 13 9 14 - # Main resolution: extract class config and recursively resolve includes 15 - resolve = class: aspect-chain: provided: { 10 + inner = class: aspect-chain: provided: { 16 11 imports = 17 12 let 18 13 config = provided.${class} or { }; ··· 24 19 ]; 25 20 }; 26 21 22 + resolve = 23 + class: aspect-chain: aspect: 24 + let 25 + provided = 26 + if lib.isFunction aspect then 27 + aspect { 28 + inherit class; 29 + aspect-chain = aspect-chain; 30 + } 31 + else 32 + aspect; 33 + in 34 + inner class aspect-chain provided; 27 35 in 28 36 resolve
+11 -23
nix/types.nix
··· 1 - # Core type system for aspect-oriented configuration 2 - 3 1 lib: 4 2 let 5 3 resolve = import ./resolve.nix lib; 6 4 7 - # Type for computed values that only exist during evaluation 8 5 ignoredType = lib.types.mkOptionType { 9 6 name = "ignored type"; 10 7 description = "ignored values"; ··· 24 21 apply = fn; 25 22 }; 26 23 27 - # Like lib.types.functionTo, but it does not merges all definitions, and keeps 28 - # just the last one. 29 - functorType = lib.mkOptionType { 24 + functorType = lib.types.mkOptionType { 30 25 name = "aspectFunctor"; 31 26 description = "aspect functor function"; 32 27 check = lib.isFunction; 33 28 merge = 34 - loc: defs: 29 + _loc: defs: 35 30 let 36 - # Use only the last definition to avoid duplication from 37 - # functionTo merging all definitions with the same args. 38 - # All definitions receive the same merged `self`, so they 39 - # produce equivalent results - picking one is correct. 40 31 lastDef = lib.last defs; 41 - innerType = providerType; 42 32 in 43 33 { 44 34 __functionArgs = lib.functionArgs lastDef.value; 45 35 __functor = 46 36 _: callerArgs: 47 - (lib.modules.mergeDefinitions (loc ++ [ "<function body>" ]) innerType [ 48 - { 49 - inherit (lastDef) file; 50 - value = lastDef.value callerArgs; 51 - } 52 - ]).mergedValue; 37 + let 38 + result = lastDef.value callerArgs; 39 + in 40 + if builtins.isFunction result then result else _: result; 53 41 }; 54 42 }; 55 43 56 - # Check if function has submodule-style arguments 57 44 isSubmoduleFn = 58 45 m: 59 - lib.length ( 60 - lib.intersectLists [ "lib" "config" "options" "aspect" ] (lib.attrNames (lib.functionArgs m)) 61 - ) > 0; 46 + let 47 + args = lib.functionArgs m; 48 + in 49 + args ? lib || args ? config || args ? options || args ? aspect; 62 50 63 51 # Check if function accepts { class } and/or { aspect-chain } 64 52 isProviderFn = 65 53 f: 66 54 let 67 55 args = lib.functionArgs f; 68 - n = lib.length (lib.attrNames args); 56 + n = builtins.length (builtins.attrNames args); 69 57 in 70 58 (args ? class && n == 1) 71 59 || (args ? aspect-chain && n == 1)