packages feed

mfmts-1.0.0.0: cid/MultiFormats/CID/Internal/CIDHash.hs

-- | Module      : MultiFormats.CID.Internal.CIDHash
--   Description : Implements extraction and verification of multihash CID data
--   Copyright   : Zoey McBride (c) 2026
--   License     : AGPL-3.0-or-later
--   Maintainer  : zoeymcbride@mailbox.org
--   Stability   : experimental
module MultiFormats.CID.Internal.CIDHash (CIDHash (CIDHash)) where

import Data.Bifunctor (first)
import Data.ByteString (ByteString)
import Data.ByteString qualified as Bytes
import MultiFormats.CID.Errors
import MultiFormats.CID.Extractor (Extractor (extractor))
import MultiFormats.CID.Internal.CIDCodec (CIDCodec (CIDCodec))
import MultiFormats.MultiHash (MultiHash, resolveHashCodec)
import MultiFormats.VarInt (VarInt)

data CIDHash = CIDHash
  { -- | Stores the MultiCodec for the hash function used.
    cidHashCodec :: MultiHash,
    -- | Stores the hash function's output.
    cidHashDigest :: ByteString
  }
  deriving (Eq)

-- | Extracts the MultiHash codec and hash digest via a varint size following
-- the MultiHash codec.
instance Extractor CIDHash where
  extractor bytes = do
    -- Get the CodecCode from the first varint
    (CIDCodec codec, onsize) <- extractor bytes
    -- Get the digest size from the first varint, make CID.Error if on Left
    (usize :: VarInt, rest) <- extractor onsize
    -- When codec is a valid hash and the given size is available in the bytes,
    -- take #size elements from bytes and construct the CIDHash
    case resolveHashCodec codec of
      Nothing -> Left (InvalidHash ExpectedHashCodec)
      Just hash
        | isize > Bytes.length rest -> Left (InvalidHash IncorrectLength)
        | otherwise -> Right (first (CIDHash hash) $ Bytes.splitAt isize rest)
        where
          isize = fromIntegral usize