From 4a724cb84cc3aa464af1713d11bf0cfbbdb56c00 Mon Sep 17 00:00:00 2001 From: rcerc <88944439+rcerc@users.noreply.github.com> Date: Thu, 13 Jan 2022 12:21:32 -0500 Subject: [PATCH] lib: improve DAG library Specifically, - directly export `modules/lib/dag.nix` instead of renaming attributes, - run through utilities to reuse code where possible, - expose `lib.hm.dag.isEntry` and reuse it in `modules/lib/types-dag.nix`, - reuse utilities through `lib` set instead of passing imports to functions, and - eta reduction of `map`, `entryAnywhere`, `entryAfter` and `entryBefore`. --- modules/lib/dag.nix | 95 +++++++++++++++++---------------------- modules/lib/default.nix | 17 +------ modules/lib/types-dag.nix | 12 +++-- modules/lib/types.nix | 5 +-- 4 files changed, 50 insertions(+), 79 deletions(-) diff --git a/modules/lib/dag.nix b/modules/lib/dag.nix index 0c0e33ee..50044a0b 100644 --- a/modules/lib/dag.nix +++ b/modules/lib/dag.nix @@ -4,39 +4,38 @@ # # - not specific to strings, i.e., any payload is OK, # -# - the addition of the function `dagEntryBefore` indicating a -# "wanted by" relationship. +# - the addition of the function `entryBefore` indicating a "wanted +# by" relationship. { lib }: -let inherit (lib) all any filterAttrs mapAttrs mapAttrsToList toposort; -in rec { - - emptyDag = { }; +let inherit (lib) all filterAttrs hm mapAttrs toposort; +in { + empty = { }; + isEntry = e: e ? data && e ? after && e ? before; isDag = dag: - let isEntry = e: (e ? data) && (e ? after) && (e ? before); - in builtins.isAttrs dag && all (x: x) (mapAttrsToList (n: isEntry) dag); + builtins.isAttrs dag && all hm.dag.isEntry (builtins.attrValues dag); - # Takes an attribute set containing entries built by - # dagEntryAnywhere, dagEntryAfter, and dagEntryBefore to a - # topologically sorted list of entries. + # Takes an attribute set containing entries built by entryAnywhere, + # entryAfter, and entryBefore to a topologically sorted list of + # entries. # # Internally this function uses the `toposort` function in # `` and its value is accordingly. # # Specifically, the result on success is # - # { result = [{name = ?; data = ?;} …] } + # { result = [ { name = ?; data = ?; } … ] } # # For example # - # nix-repl> dagTopoSort { - # a = dagEntryAnywhere "1"; - # b = dagEntryAfter ["a" "c"] "2"; - # c = dagEntryBefore ["d"] "3"; - # d = dagEntryBefore ["e"] "4"; - # e = dagEntryAnywhere "5"; + # nix-repl> topoSort { + # a = entryAnywhere "1"; + # b = entryAfter [ "a" "c" ] "2"; + # c = entryBefore [ "d" ] "3"; + # d = entryBefore [ "e" ] "4"; + # e = entryAnywhere "5"; # } == { # result = [ # { data = "1"; name = "a"; } @@ -51,66 +50,54 @@ in rec { # And the result on error is # # { - # cycle = [ {after = ?; name = ?; data = ?} … ]; - # loops = [ {after = ?; name = ?; data = ?} … ]; + # cycle = [ { after = ?; name = ?; data = ? } … ]; + # loops = [ { after = ?; name = ?; data = ? } … ]; # } # # For example # - # nix-repl> dagTopoSort { - # a = dagEntryAnywhere "1"; - # b = dagEntryAfter ["a" "c"] "2"; - # c = dagEntryAfter ["d"] "3"; - # d = dagEntryAfter ["b"] "4"; - # e = dagEntryAnywhere "5"; + # nix-repl> topoSort { + # a = entryAnywhere "1"; + # b = entryAfter [ "a" "c" ] "2"; + # c = entryAfter [ "d" ] "3"; + # d = entryAfter [ "b" ] "4"; + # e = entryAnywhere "5"; # } == { # cycle = [ - # { after = ["a" "c"]; data = "2"; name = "b"; } - # { after = ["d"]; data = "3"; name = "c"; } - # { after = ["b"]; data = "4"; name = "d"; } + # { after = [ "a" "c" ]; data = "2"; name = "b"; } + # { after = [ "d" ]; data = "3"; name = "c"; } + # { after = [ "b" ]; data = "4"; name = "d"; } # ]; # loops = [ - # { after = ["a" "c"]; data = "2"; name = "b"; } + # { after = [ "a" "c" ]; data = "2"; name = "b"; } # ]; - # } == {} + # } # true - dagTopoSort = dag: + topoSort = dag: let dagBefore = dag: name: - mapAttrsToList (n: v: n) - (filterAttrs (n: v: any (a: a == name) v.before) dag); + builtins.attrNames + (filterAttrs (n: v: builtins.elem name v.before) dag); normalizedDag = mapAttrs (n: v: { name = n; data = v.data; after = v.after ++ dagBefore dag n; }) dag; - before = a: b: any (c: a.name == c) b.after; - sorted = toposort before (mapAttrsToList (n: v: v) normalizedDag); + before = a: b: builtins.elem a.name b.after; + sorted = toposort before (builtins.attrValues normalizedDag); in if sorted ? result then { result = map (v: { inherit (v) name data; }) sorted.result; } else sorted; # Applies a function to each element of the given DAG. - dagMap = f: dag: mapAttrs (n: v: v // { data = f n v.data; }) dag; + map = f: mapAttrs (n: v: v // { data = f n v.data; }); + + entryBetween = before: after: data: { inherit data before after; }; # Create a DAG entry with no particular dependency information. - dagEntryAnywhere = data: { - inherit data; - before = [ ]; - after = [ ]; - }; - - dagEntryBetween = before: after: data: { inherit data before after; }; - - dagEntryAfter = after: data: { - inherit data after; - before = [ ]; - }; - - dagEntryBefore = before: data: { - inherit data before; - after = [ ]; - }; + entryAnywhere = hm.dag.entryBetween [ ] [ ]; + entryAfter = hm.dag.entryBetween [ ]; + entryBefore = before: hm.dag.entryBetween before [ ]; } diff --git a/modules/lib/default.nix b/modules/lib/default.nix index 580316e0..59f707c4 100644 --- a/modules/lib/default.nix +++ b/modules/lib/default.nix @@ -1,20 +1,7 @@ { lib }: rec { - dag = - let - d = import ./dag.nix { inherit lib; }; - in - { - empty = d.emptyDag; - isDag = d.isDag; - topoSort = d.dagTopoSort; - map = d.dagMap; - entryAnywhere = d.dagEntryAnywhere; - entryBetween = d.dagEntryBetween; - entryAfter = d.dagEntryAfter; - entryBefore = d.dagEntryBefore; - }; + dag = import ./dag.nix { inherit lib; }; assertions = import ./assertions.nix { inherit lib; }; @@ -22,7 +9,7 @@ rec { gvariant = import ./gvariant.nix { inherit lib; }; maintainers = import ./maintainers.nix; strings = import ./strings.nix { inherit lib; }; - types = import ./types.nix { inherit dag gvariant lib; }; + types = import ./types.nix { inherit gvariant lib; }; shell = import ./shell.nix { inherit lib; }; zsh = import ./zsh.nix { inherit lib; }; diff --git a/modules/lib/types-dag.nix b/modules/lib/types-dag.nix index e793940e..46694f2a 100644 --- a/modules/lib/types-dag.nix +++ b/modules/lib/types-dag.nix @@ -1,13 +1,11 @@ -{ dag, lib }: +{ lib }: let inherit (lib) - concatStringsSep defaultFunctor fixedWidthNumber imap1 isAttrs isList length - listToAttrs mapAttrs mkIf mkOrder mkOption mkOptionType nameValuePair + concatStringsSep defaultFunctor fixedWidthNumber hm imap1 isAttrs isList + length listToAttrs mapAttrs mkIf mkOrder mkOption mkOptionType nameValuePair stringLength types warn; - isDagEntry = e: isAttrs e && (e ? data) && (e ? after) && (e ? before); - dagEntryOf = elemType: let submoduleType = types.submodule ({ name, ... }: { @@ -21,10 +19,10 @@ let }; }); maybeConvert = def: - if isDagEntry def.value then + if hm.dag.isEntry def.value then def.value else - dag.entryAnywhere (if def ? priority then + hm.dag.entryAnywhere (if def ? priority then mkOrder def.priority def.value else def.value); diff --git a/modules/lib/types.nix b/modules/lib/types.nix index 71ec587f..d2ed24a3 100644 --- a/modules/lib/types.nix +++ b/modules/lib/types.nix @@ -1,5 +1,4 @@ -{ lib, dag ? import ./dag.nix { inherit lib; } -, gvariant ? import ./gvariant.nix { inherit lib; } }: +{ lib, gvariant ? import ./gvariant.nix { inherit lib; } }: let inherit (lib) @@ -7,7 +6,7 @@ let mergeAttrs mergeDefaultOption mergeOneOption mergeOptions mkOption mkOptionType showFiles showOption types; - typesDag = import ./types-dag.nix { inherit dag lib; }; + typesDag = import ./types-dag.nix { inherit lib; }; # Needed since the type is called gvariant and its merge attribute # must refer back to the type.