module Unison.Hash
  ( Hash (Hash),
    HashFor (..),

    -- ** ShortByteString conversions
    toShort,

    -- ** ByteString conversions
    fromByteString,
    toByteString,

    -- ** Base32Hex conversions
    fromBase32Hex,
    toBase32Hex,

    -- ** Base32Hex Text conversions
    fromBase32HexText,
    unsafeFromBase32HexText,
    toBase32HexText,
  )
where

import Data.ByteString.Short (ShortByteString)
import Data.ByteString.Short qualified as B.Short
import U.Util.Base32Hex (Base32Hex)
import U.Util.Base32Hex qualified as Base32Hex
import Unison.Prelude

-- | A hash.
newtype Hash = Hash {Hash -> ShortByteString
toShort :: ShortByteString}
  deriving stock (Hash -> Hash -> Bool
(Hash -> Hash -> Bool) -> (Hash -> Hash -> Bool) -> Eq Hash
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Hash -> Hash -> Bool
== :: Hash -> Hash -> Bool
$c/= :: Hash -> Hash -> Bool
/= :: Hash -> Hash -> Bool
Eq, Eq Hash
Eq Hash =>
(Hash -> Hash -> Ordering)
-> (Hash -> Hash -> Bool)
-> (Hash -> Hash -> Bool)
-> (Hash -> Hash -> Bool)
-> (Hash -> Hash -> Bool)
-> (Hash -> Hash -> Hash)
-> (Hash -> Hash -> Hash)
-> Ord Hash
Hash -> Hash -> Bool
Hash -> Hash -> Ordering
Hash -> Hash -> Hash
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Hash -> Hash -> Ordering
compare :: Hash -> Hash -> Ordering
$c< :: Hash -> Hash -> Bool
< :: Hash -> Hash -> Bool
$c<= :: Hash -> Hash -> Bool
<= :: Hash -> Hash -> Bool
$c> :: Hash -> Hash -> Bool
> :: Hash -> Hash -> Bool
$c>= :: Hash -> Hash -> Bool
>= :: Hash -> Hash -> Bool
$cmax :: Hash -> Hash -> Hash
max :: Hash -> Hash -> Hash
$cmin :: Hash -> Hash -> Hash
min :: Hash -> Hash -> Hash
Ord, (forall x. Hash -> Rep Hash x)
-> (forall x. Rep Hash x -> Hash) -> Generic Hash
forall x. Rep Hash x -> Hash
forall x. Hash -> Rep Hash x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Hash -> Rep Hash x
from :: forall x. Hash -> Rep Hash x
$cto :: forall x. Rep Hash x -> Hash
to :: forall x. Rep Hash x -> Hash
Generic)

instance Show Hash where
  show :: Hash -> String
show = Text -> String
forall a. Show a => a -> String
show (Text -> String) -> (Hash -> Text) -> Hash -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Hash -> Text
toBase32HexText

-- | A hash tagged with the type it's a hash of, useful for maintaining type safety guarantees.
newtype HashFor t = HashFor {forall t. HashFor t -> Hash
genericHash :: Hash}
  deriving newtype (Int -> HashFor t -> ShowS
[HashFor t] -> ShowS
HashFor t -> String
(Int -> HashFor t -> ShowS)
-> (HashFor t -> String)
-> ([HashFor t] -> ShowS)
-> Show (HashFor t)
forall t. Int -> HashFor t -> ShowS
forall t. [HashFor t] -> ShowS
forall t. HashFor t -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall t. Int -> HashFor t -> ShowS
showsPrec :: Int -> HashFor t -> ShowS
$cshow :: forall t. HashFor t -> String
show :: HashFor t -> String
$cshowList :: forall t. [HashFor t] -> ShowS
showList :: [HashFor t] -> ShowS
Show, HashFor t -> HashFor t -> Bool
(HashFor t -> HashFor t -> Bool)
-> (HashFor t -> HashFor t -> Bool) -> Eq (HashFor t)
forall t. HashFor t -> HashFor t -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall t. HashFor t -> HashFor t -> Bool
== :: HashFor t -> HashFor t -> Bool
$c/= :: forall t. HashFor t -> HashFor t -> Bool
/= :: HashFor t -> HashFor t -> Bool
Eq, Eq (HashFor t)
Eq (HashFor t) =>
(HashFor t -> HashFor t -> Ordering)
-> (HashFor t -> HashFor t -> Bool)
-> (HashFor t -> HashFor t -> Bool)
-> (HashFor t -> HashFor t -> Bool)
-> (HashFor t -> HashFor t -> Bool)
-> (HashFor t -> HashFor t -> HashFor t)
-> (HashFor t -> HashFor t -> HashFor t)
-> Ord (HashFor t)
HashFor t -> HashFor t -> Bool
HashFor t -> HashFor t -> Ordering
HashFor t -> HashFor t -> HashFor t
forall t. Eq (HashFor t)
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall t. HashFor t -> HashFor t -> Bool
forall t. HashFor t -> HashFor t -> Ordering
forall t. HashFor t -> HashFor t -> HashFor t
$ccompare :: forall t. HashFor t -> HashFor t -> Ordering
compare :: HashFor t -> HashFor t -> Ordering
$c< :: forall t. HashFor t -> HashFor t -> Bool
< :: HashFor t -> HashFor t -> Bool
$c<= :: forall t. HashFor t -> HashFor t -> Bool
<= :: HashFor t -> HashFor t -> Bool
$c> :: forall t. HashFor t -> HashFor t -> Bool
> :: HashFor t -> HashFor t -> Bool
$c>= :: forall t. HashFor t -> HashFor t -> Bool
>= :: HashFor t -> HashFor t -> Bool
$cmax :: forall t. HashFor t -> HashFor t -> HashFor t
max :: HashFor t -> HashFor t -> HashFor t
$cmin :: forall t. HashFor t -> HashFor t -> HashFor t
min :: HashFor t -> HashFor t -> HashFor t
Ord, (forall x. HashFor t -> Rep (HashFor t) x)
-> (forall x. Rep (HashFor t) x -> HashFor t)
-> Generic (HashFor t)
forall x. Rep (HashFor t) x -> HashFor t
forall x. HashFor t -> Rep (HashFor t) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall t x. Rep (HashFor t) x -> HashFor t
forall t x. HashFor t -> Rep (HashFor t) x
$cfrom :: forall t x. HashFor t -> Rep (HashFor t) x
from :: forall x. HashFor t -> Rep (HashFor t) x
$cto :: forall t x. Rep (HashFor t) x -> HashFor t
to :: forall x. Rep (HashFor t) x -> HashFor t
Generic)

instance From Hash Text where
  from :: Hash -> Text
from = Hash -> Text
toBase32HexText

-- | Convert a hash to a byte string.
toByteString :: Hash -> ByteString
toByteString :: Hash -> ByteString
toByteString = ShortByteString -> ByteString
B.Short.fromShort (ShortByteString -> ByteString)
-> (Hash -> ShortByteString) -> Hash -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Hash -> ShortByteString
toShort

-- | Convert a byte string to a hash.
fromByteString :: ByteString -> Hash
fromByteString :: ByteString -> Hash
fromByteString = ShortByteString -> Hash
Hash (ShortByteString -> Hash)
-> (ByteString -> ShortByteString) -> ByteString -> Hash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ShortByteString
B.Short.toShort

-- | Convert base32 hex to a hash.
fromBase32Hex :: Base32Hex -> Hash
fromBase32Hex :: Base32Hex -> Hash
fromBase32Hex = ByteString -> Hash
fromByteString (ByteString -> Hash)
-> (Base32Hex -> ByteString) -> Base32Hex -> Hash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Base32Hex -> ByteString
Base32Hex.toByteString

-- | Convert a hash to base32 hex.
toBase32Hex :: Hash -> Base32Hex
toBase32Hex :: Hash -> Base32Hex
toBase32Hex = ByteString -> Base32Hex
Base32Hex.fromByteString (ByteString -> Base32Hex)
-> (Hash -> ByteString) -> Hash -> Base32Hex
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Hash -> ByteString
toByteString

-- | Produce a 'Hash' from a base32hex-encoded version of its binary representation
fromBase32HexText :: Text -> Maybe Hash
fromBase32HexText :: Text -> Maybe Hash
fromBase32HexText = (Base32Hex -> Hash) -> Maybe Base32Hex -> Maybe Hash
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Base32Hex -> Hash
fromBase32Hex (Maybe Base32Hex -> Maybe Hash)
-> (Text -> Maybe Base32Hex) -> Text -> Maybe Hash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Maybe Base32Hex
Base32Hex.fromText

-- | Convert a hash from base32 hex without any validation.
unsafeFromBase32HexText :: Text -> Hash
unsafeFromBase32HexText :: Text -> Hash
unsafeFromBase32HexText = Base32Hex -> Hash
fromBase32Hex (Base32Hex -> Hash) -> (Text -> Base32Hex) -> Text -> Hash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Base32Hex
Base32Hex.UnsafeFromText

-- | Return the lowercase unpadded base32Hex encoding of this 'Hash'.
-- Multibase prefix would be 'v', see https://github.com/multiformats/multibase
toBase32HexText :: Hash -> Text
toBase32HexText :: Hash -> Text
toBase32HexText = Base32Hex -> Text
Base32Hex.toText (Base32Hex -> Text) -> (Hash -> Base32Hex) -> Hash -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Hash -> Base32Hex
toBase32Hex