diff --git a/subprojects/bahaghari/lib/default.nix b/subprojects/bahaghari/lib/default.nix index 3f4f73a7..3dde29ca 100644 --- a/subprojects/bahaghari/lib/default.nix +++ b/subprojects/bahaghari/lib/default.nix @@ -21,6 +21,6 @@ pkgs.lib.makeExtensible tinted-theming = callLibs ./tinted-theming.nix; inherit (self.trivial) importYAML toYAML toBaseDigitsWithGlyphs - generateGlyphSet generateConversionTable pow; - inherit (self.hex) toHexString isHexString hexToDec; + generateGlyphSet generateConversionTable generateBaseDigitType pow; + }) diff --git a/subprojects/bahaghari/lib/trivial.nix b/subprojects/bahaghari/lib/trivial.nix index d712d88a..76f8eb6d 100644 --- a/subprojects/bahaghari/lib/trivial.nix +++ b/subprojects/bahaghari/lib/trivial.nix @@ -1,6 +1,6 @@ { pkgs, lib }: -{ +rec { inherit (pkgs.lib.generators) toYAML; /* Read YAML files into a Nix expression similar to lib.importJSON and @@ -99,6 +99,59 @@ in pkgs.lib.listToAttrs glyphsList'; + /* A factory function for generating an attribute set containing a glyph + set, a conversion table, and a conversion function to and from decimal. + Accepts the same list as `generateGlyphSet` and + `generateConversionTable` where it assumes it is sorted and + zero-indexed. + + Type: generateBaseDigitType :: [ String ] -> Attrs + + Example: + generateBaseDigitType [ "0" "1" ] + => { + base = 2; + glyphSet = { "0" = "0"; "1" = "1"; }; + conversionTable = { "0" = 0; "1" = 1; }; + isValidDigit = <function>; + fromDec = <function>; + toDec = <function>; + } + */ + generateBaseDigitType = glyphsList: rec { + base = pkgs.lib.length glyphsList; + glyphSet = generateGlyphSet glyphsList; + conversionTable = generateConversionTable glyphsList; + + # Unfortunately, these functions cannot handle negative numbers unless we + # implement something like Two's complement. For now, we're not worrying + # about that since most of the use cases here will be mostly for color + # generation that typically uses hexadecimal (RGB). Plus I don't want to + # open a can of worms about implementing this with stringy types. + fromDec = decimal: + let + iter = product: value: + let + quotient = value / base; + remainder = value - (base * quotient); + baseDigit = glyphSet.${builtins.toString remainder} + product; + in + if quotient <= 0 + then baseDigit + else iter baseDigit quotient; + in + iter "" decimal; + + toDec = digit: + let + chars = pkgs.lib.stringToCharacters digit; + maxDigits = (pkgs.lib.length chars) - 1; + convertDigitToDec = + pkgs.lib.lists.imap0 (i: v: conversionTable.${v} * (pow base (maxDigits - i))) chars; + in + pkgs.lib.foldl (sum: v: sum + v) 0 convertDigitToDec; + }; + /* Exponentiates the given base with the exponent. Type: pow :: Int -> Int -> Int diff --git a/subprojects/bahaghari/tests/lib/trivial/default.nix b/subprojects/bahaghari/tests/lib/trivial/default.nix index 05c9a6f7..0f2e507d 100644 --- a/subprojects/bahaghari/tests/lib/trivial/default.nix +++ b/subprojects/bahaghari/tests/lib/trivial/default.nix @@ -12,6 +12,33 @@ let "7" = "H"; }; + base24GlyphsList = [ + "0" + "1" + "2" + "3" + "4" + "5" + "6" + "7" + "8" + "9" + "A" + "B" + "C" + "D" + "E" + "F" + "G" + "H" + "I" + "J" + "K" + "L" + "M" + "N" + ]; + customBase24Glyphs = { "0" = "0"; "1" = "1"; @@ -33,11 +60,13 @@ let "17" = "H"; "18" = "I"; "19" = "J"; - "20" = "M"; - "21" = "N"; - "22" = "O"; - "23" = "P"; + "20" = "K"; + "21" = "L"; + "22" = "M"; + "23" = "N"; }; + + base24Set = lib.trivial.generateBaseDigitType base24GlyphsList; in pkgs.lib.runTests { testGenerateCustomGlyphSet = { @@ -46,34 +75,7 @@ pkgs.lib.runTests { }; testGenerateBase24GlyphSet = { - expr = - lib.trivial.generateGlyphSet - [ - "0" - "1" - "2" - "3" - "4" - "5" - "6" - "7" - "8" - "9" - "A" - "B" - "C" - "D" - "E" - "F" - "G" - "H" - "I" - "J" - "M" - "N" - "O" - "P" - ]; + expr = lib.trivial.generateGlyphSet base24GlyphsList; expected = customBase24Glyphs; }; @@ -91,6 +93,41 @@ pkgs.lib.runTests { }; }; + testGenerateConversionTable2 = { + expr = lib.trivial.generateConversionTable + [ "0" "1" "2" "3" "4" "5" "6" "7" + "8" "9" "A" "B" "C" "D" "E" "F" ]; + expected = { + "0" = 0; + "1" = 1; + "2" = 2; + "3" = 3; + "4" = 4; + "5" = 5; + "6" = 6; + "7" = 7; + "8" = 8; + "9" = 9; + "A" = 10; + "B" = 11; + "C" = 12; + "D" = 13; + "E" = 14; + "F" = 15; + }; + }; + + # Testing out the custom factory methods if they are working as intended. + testCustomBaseDigitSetToDec = { + expr = base24Set.toDec "12H"; + expected = 641; + }; + + testCustomBaseDigitSetFromDec = { + expr = base24Set.fromDec 641; + expected = "12H"; + }; + testBaseDigitWithCustomOctalGlyph = { expr = lib.trivial.toBaseDigitsWithGlyphs 8 9 customOctalGlyphs; expected = "BB";