├── bottom.nix ├── license └── readme.md /bottom.nix: -------------------------------------------------------------------------------- 1 | let 2 | hexDigit = d: 3 | if d < 10 then builtins.toString d 4 | else { 5 | "10" = "a"; 6 | "11" = "b"; 7 | "12" = "c"; 8 | "13" = "d"; 9 | "14" = "e"; 10 | "15" = "f"; 11 | }.${builtins.toString d}; 12 | 13 | hexByte = n: let 14 | upper = n / 16; 15 | lower = n - (16 * upper); 16 | in "${hexDigit upper}${hexDigit lower}"; 17 | 18 | genByte = n: 19 | if n < 128 then builtins.fromJSON ''"\u00${hexByte n}"'' 20 | else if n < 192 then builtins.substring 1 1 (builtins.fromJSON ''"\u00${hexByte n}"'') 21 | else if n < 194 then null 22 | else if n == 194 then builtins.substring 0 1 (builtins.fromJSON ''"\u0080"'') 23 | else if n == 195 then builtins.substring 0 1 (builtins.fromJSON ''"\u00f0"'') 24 | else if n < 224 then builtins.substring 0 1 (builtins.fromJSON ''"\u0${hexByte ((n - 192) * 4)}0"'') 25 | else if n == 224 then builtins.substring 0 1 (builtins.fromJSON ''"\u${hexDigit (n - 224)}800"'') 26 | else if n < 240 then builtins.substring 0 1 (builtins.fromJSON ''"\u${hexDigit (n - 224)}7ff"'') 27 | else if n == 240 then builtins.substring 0 1 (builtins.fromJSON ''"\ud800\udc00"'') 28 | else if n == 241 then builtins.substring 0 1 (builtins.fromJSON ''"\ud8c0\udc00"'') 29 | else if n < 243 then null 30 | else if n == 243 then builtins.substring 0 1 (builtins.fromJSON ''"\ud9c0\udc00"'') 31 | else if n == 244 then builtins.substring 0 1 (builtins.fromJSON ''"\udac0\udc00"'') 32 | else if n == 245 then builtins.substring 0 1 (builtins.fromJSON ''"\udbc0\udc00"'') 33 | else null; 34 | 35 | byteTable = builtins.listToAttrs (builtins.filter (e: e.name != null) (builtins.genList (n: { name = genByte n; value = n; }) 255)); 36 | invByteTable = builtins.listToAttrs (builtins.map (name: { name = builtins.toString (builtins.getAttr name byteTable); value = name; }) (builtins.attrNames byteTable)); 37 | 38 | byteList = input: builtins.genList (n: builtins.getAttr (builtins.substring n 1 input) byteTable) (builtins.stringLength input); 39 | 40 | splitString = regex: string: builtins.filter builtins.isString (builtins.split regex string); 41 | removeSuffix = suffix: string: builtins.substring 0 ((builtins.stringLength string) - (builtins.stringLength suffix)) string; 42 | in rec { 43 | encodeFile = filename: encode (builtins.readFile filename); 44 | encode = input: let 45 | encodeNonZeroByte = byte: 46 | if byte >= 200 then [ "🫂" ] ++ encodeNonZeroByte (byte - 200) 47 | else if byte >= 50 then [ "💖" ] ++ encodeNonZeroByte (byte - 50) 48 | else if byte >= 10 then [ "✨" ] ++ encodeNonZeroByte (byte - 10) 49 | else if byte >= 5 then [ "🥺" ] ++ encodeNonZeroByte (byte - 5) 50 | else if byte >= 1 then [ "," ] ++ encodeNonZeroByte (byte - 1) 51 | else []; 52 | encodeByte = byte: (if byte == 0 then [ "❤️" ] else encodeNonZeroByte byte) ++ [ "👉👈" ]; 53 | in builtins.concatStringsSep "" (builtins.concatLists (builtins.map encodeByte (byteList input))); 54 | 55 | decodeFile = filename: decode (builtins.readFile filename); 56 | decode = input: let 57 | decodeByte = byte: let 58 | numberedString = builtins.replaceStrings [ "🫂" "💖" "✨" "🥺" "," ] [ "200," "50," "10," "5," "1," ] byte; 59 | numbered = builtins.map builtins.fromJSON (splitString "," (removeSuffix "," numberedString)); 60 | in builtins.getAttr (builtins.toString (builtins.foldl' builtins.add 0 numbered)) invByteTable; 61 | in builtins.concatStringsSep "" (builtins.map decodeByte (splitString "👉👈" (removeSuffix "👉👈" input))); 62 | } 63 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2024, Lily Foster 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # bottom-nix 2 | 3 | An implementation of the [Bottom encoding format](https://github.com/bottom-software-foundation/spec) in Nix 4 | 5 | 6 | ## Usage 7 | 8 | ```sh 9 | nix eval --raw -f bottom.nix --apply 'bottom: bottom.encodeFile ./bottom.nix' 10 | ``` 11 | --------------------------------------------------------------------------------