-- | Implementation of base-62 encoding, which we use when computing hashes
-- for fully instantiated unit ids.
module Distribution.Utils.Base62 (hashToBase62) where

import Data.Char (chr)
import GHC.Fingerprint (Fingerprint (..), fingerprintString)
import Numeric (showIntAtBase)

-- | Hash a string using GHC's fingerprinting algorithm (a 128-bit
-- MD5 hash) and then encode the resulting hash in base 62.
hashToBase62 :: String -> String
hashToBase62 :: String -> String
hashToBase62 String
s = Fingerprint -> String
showFingerprint (Fingerprint -> String) -> Fingerprint -> String
forall a b. (a -> b) -> a -> b
$ String -> Fingerprint
fingerprintString String
s
  where
    showIntAtBase62 :: a -> String
showIntAtBase62 a
x = a -> (Int -> Char) -> a -> String -> String
forall a. Integral a => a -> (Int -> Char) -> a -> String -> String
showIntAtBase a
62 Int -> Char
representBase62 a
x String
""
    representBase62 :: Int -> Char
representBase62 Int
x
      | Int
x Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
10 = Int -> Char
chr (Int
48 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
x)
      | Int
x Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
36 = Int -> Char
chr (Int
65 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
x Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
10)
      | Int
x Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
62 = Int -> Char
chr (Int
97 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
x Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
36)
      | Bool
otherwise = Char
'@'
    showFingerprint :: Fingerprint -> String
showFingerprint (Fingerprint Word64
a Word64
b) = Word64 -> String
forall {a}. Integral a => a -> String
showIntAtBase62 Word64
a String -> String -> String
forall a. [a] -> [a] -> [a]
++ Word64 -> String
forall {a}. Integral a => a -> String
showIntAtBase62 Word64
b