module Data.Hash.SL2
( Hash
, hash
, append, prepend
, foldAppend, foldPrepend
, unit, concat, concatAll
, parse
, valid, validate
, pack8, pack16, pack32, pack64
, unpack8, unpack16, unpack32, unpack64
) where
import Prelude hiding (concat)
import Data.Hash.SL2.Internal (Hash)
import Data.Hash.SL2.Unsafe
import qualified Data.Hash.SL2.Mutable as Mutable
import System.IO.Unsafe
import Data.ByteString (ByteString)
import Data.Word
import Data.Monoid
import Data.Functor
import Data.Foldable (Foldable)
instance Show Hash where
show h = unsafePerformIO $ unsafeUseAsPtr h Mutable.serialize
instance Eq Hash where
a == b = unsafePerformIO $ unsafeUseAsPtr2 a b Mutable.eq
instance Monoid Hash where
mempty = unit
mappend = concat
mconcat = concatAll
hash :: ByteString -> Hash
hash = append unit
append :: Hash -> ByteString -> Hash
append h s = fst $ unsafePerformIO $ Mutable.withCopy h $ Mutable.append s
prepend :: ByteString -> Hash -> Hash
prepend s h = fst $ unsafePerformIO $ Mutable.withCopy h $ Mutable.prepend s
foldAppend :: Foldable t => Hash -> t ByteString -> Hash
foldAppend h ss = fst $ unsafePerformIO $ Mutable.withCopy h $ Mutable.foldAppend ss
foldPrepend :: Foldable t => t ByteString -> Hash -> Hash
foldPrepend ss h = fst $ unsafePerformIO $ Mutable.withCopy h $ Mutable.foldPrepend ss
unit :: Hash
unit = fst $ unsafePerformIO $ unsafeWithNew Mutable.unit
concat :: Hash -> Hash -> Hash
concat a b = fst $ unsafePerformIO $ unsafeWithNew (unsafeUseAsPtr2 a b . Mutable.concat)
concatAll :: [Hash] -> Hash
concatAll [] = unit
concatAll [h] = h
concatAll (h:hs) = fst $ unsafePerformIO $ Mutable.withCopy h $ \p ->
mapM_ (flip unsafeUseAsPtr $ Mutable.concat p p) hs
parse :: String -> Maybe Hash
parse s = (\(h, r) -> h <$ r) $ unsafePerformIO $ unsafeWithNew $ Mutable.unserialize s
valid :: Hash -> Bool
valid h = unsafePerformIO $ unsafeUseAsPtr h Mutable.valid
validate :: Hash -> Maybe Hash
validate h | valid h = Just h
validate _ = Nothing
pack8 :: [Word8] -> Maybe Hash
pack8 ws | length ws == 64 = validate (unsafePack ws)
pack8 _ = Nothing
pack16 :: [Word16] -> Maybe Hash
pack16 ws | length ws == 32 = validate (unsafePack ws)
pack16 _ = Nothing
pack32 :: [Word32] -> Maybe Hash
pack32 ws | length ws == 16 = validate (unsafePack ws)
pack32 _ = Nothing
pack64 :: [Word64] -> Maybe Hash
pack64 ws | length ws == 8 = validate (unsafePack ws)
pack64 _ = Nothing
unpack8 :: Hash -> [Word8]
unpack8 h = unsafeUnpack h
unpack16 :: Hash -> [Word16]
unpack16 h = unsafeUnpack h
unpack32 :: Hash -> [Word32]
unpack32 h = unsafeUnpack h
unpack64 :: Hash -> [Word64]
unpack64 h = unsafeUnpack h