-- | Bimap between 'Word8' an an arbitrary (ordered) type. Values of type
-- 'Word8Bimap' have to be constructed carefully to contain values for
-- all 256 'Word8' values, or the API will not be safe to use.
module Data.Text.PgpWordlist.Internal.Word8Bimap (
      Word8Bimap
    , unsafeConstruct
    , lookupL
    , lookupR
) where



import           Data.Map    (Map)
import qualified Data.Map    as M
import           Data.Vector (Vector, (!))
import qualified Data.Vector as V

import Data.Tuple
import Data.Word



-- | Bimap where one of the keys is (of the size of) a 'Word8'.
data Word8Bimap a = Bimap (Vector a) (Map a Word8)



-- | Create a 'Word8Bimap' from an association list.
--
-- The list must contain all 'Word8' in order to make the API operating on
-- the result safe.
unsafeConstruct :: Ord a => [(Word8, a)] -> Word8Bimap a
unsafeConstruct assocs = Bimap vec inverseMap
  where
    vec = V.fromList (map snd assocs)
    inverseMap = M.fromList (map swap assocs)



-- | Get the value corresponding to an index.
lookupL :: Word8Bimap a -> Word8 -> a
lookupL (Bimap l _) i = l ! fromIntegral i

-- | Get the index corresponding to a value, if present.
lookupR :: Ord a => Word8Bimap a -> a -> Maybe Word8
lookupR (Bimap _ r) i = M.lookup i r