{ pkgs, lib, self }: rec { /* Force a numerical value to be a floating value. Example: toFloat 5698 => 5698.0 toFloat 9859.55 => 9859.55 */ toFloat = x: x / 1.0; /* Count the attributes with the given predicate. Examples: countAttrs (name: value: value) { d = true; f = true; a = false; } => 2 countAttrs (name: value: value.enable) { d = { enable = true; }; f = { enable = false; package = [ ]; }; } => 1 */ countAttrs = pred: attrs: lib.count (attr: pred attr.name attr.value) (lib.mapAttrsToList lib.nameValuePair attrs); /* Filters and groups the attribute set into two separate attribute where it either accepted or denied from a given predicate function. Example: filterAttrs' (n: v: v == 4) { a = 4; b = 2; c = 6; } => { ok = { a = 4; }; notOk = { b = 2; c = 6; }; } */ filterAttrs' = f: attrs: lib.foldlAttrs (acc: name: value: let isOk = f name value; in { ok = acc.ok // lib.optionalAttrs isOk { ${name} = value; }; notOk = acc.notOk // lib.optionalAttrs (!isOk) { ${name} = value; }; }) { ok = { }; notOk = { }; } attrs; /* Convenient function for converting bits to bytes. Example: bitsToBytes 1600 => 200 */ bitsToBytes = x: x / 8.0; /* Gives the exponent with the associated SI prefix. Example: SIPrefixExponent "M" => 6 SIPrefixExponent "Q" => 30 */ SIPrefixExponent = c: let prefixes = { Q = 30; R = 27; Y = 24; Z = 21; E = 18; P = 15; T = 12; G = 9; M = 6; k = 3; h = 2; da = 1; d = -1; c = -2; m = -3; "μ" = -6; n = -9; p = -12; f = -15; a = -18; z = -21; y = -24; r = -27; q = -30; }; in prefixes.${c}; /* Gives the multiplier for the metric units. Example: metricPrefixMultiplier "M" => 1000000 metricPrefixMultiplier "G" => 1000000000 */ metricPrefixMultiplier = c: self.math.pow 10 (SIPrefixExponent c); /* Gives the exponent with the associated binary prefix. As an implementation detail, we don't follow the proper IEC unit prefixes and instead mapping this to the SI prefix for convenience. Example: SIPrefixExponent "M" => 6 SIPrefixExponent "Q" => 30 */ binaryPrefixExponent = c: let prefixes = { Y = 80; Z = 70; E = 60; P = 50; T = 40; G = 30; M = 20; K = 10; }; in prefixes.${c}; /* Gives the multiplier for the given byte unit. Essentially returns the value in number of bytes. Example: binaryPrefixMultiplier "M" => 1048576 binaryPrefixMultiplier "G" => 1.099511628×10¹² */ binaryPrefixMultiplier = c: self.math.pow 2 (binaryPrefixExponent c); /* Parse the given string containing the size into its appropriate value. Returns the value in number of bytes. Example: parseBytesSizeIntoInt "4GiB" => 4294967296 parseBytesSizeIntoInt "2 MB" => 2000000 parseBytesSizeIntoInt "2 Mb" => 250000 */ parseBytesSizeIntoInt = str: let matches = builtins.match "([[:digit:]]+)[[:space:]]*([[:alpha:]]{1})(i?[B|b])" str; numeral = lib.toInt (lib.lists.head matches); prefix = lib.lists.elemAt matches 1; suffix = lib.lists.last matches; isBinary = lib.hasPrefix "i" suffix; multiplier = let multiplierFn = if isBinary then binaryPrefixMultiplier else metricPrefixMultiplier; in multiplierFn prefix; bitDivider = if lib.hasSuffix "b" suffix then 8 else 1; in numeral * multiplier / bitDivider; /* Given an attrset of unit size object, return the size in bytes. Example: unitsToInt { size = 4; prefix = "G"; type = "binary"; } => 4294967296 unitsToInt { size = 4; prefix = "G"; type = "metric"; } => 4000000000 */ unitsToInt = { size, prefix, type ? "binary" }: let multiplierFn = if type == "binary" then binaryPrefixMultiplier else if type == "metric" then metricPrefixMultiplier else builtins.throw "no multiplier type ${type}"; in size * (multiplierFn prefix); }