{-# LANGUAGE DataKinds                  #-}
{-# LANGUAGE FlexibleInstances          #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE TypeApplications           #-}

-- |
-- Copyright   : 2019 Monadic GmbH
-- License     : BSD3
-- Maintainer  : kim@monadic.xyz, alfredo@monadic.xyz, team@monadic.xyz
-- Stability   : provisional
-- Portability : non-portable (GHC extensions)
--
-- <https://github.com/multiformats/multibase multibase> encoding of strict 'ByteString's.
--

module Data.ByteString.Multibase
    ( -- * Supported bases
      BaseN.Base(..)
    , ToCode

    -- * Multibase encoding and decoding
    , Multibase
    , fromMultibase
    , encodedBytes
    , encode
    , decode

    -- * Compact represenation
    , CompactMultibase
    , compact
    , expand
    )
where

import           Control.DeepSeq (NFData)
import           Data.ByteString (ByteString)
import           Data.ByteString.BaseN (AtBase, ValidBase)
import qualified Data.ByteString.BaseN as BaseN
import qualified Data.ByteString.Char8 as C8
import           Data.ByteString.Short (ShortByteString, fromShort, toShort)
import           Data.Coerce (coerce)
import           Data.Hashable (Hashable)
import           Data.Typeable

-- $setup
-- >>> :set -XOverloadedStrings
-- >>> import Test.QuickCheck
-- >>> import qualified Data.ByteString as BS
-- >>> newtype Bytes = Bytes ByteString deriving (Eq, Show)
-- >>> instance Arbitrary Bytes where arbitrary = Bytes . BS.pack <$> arbitrary


-- Bases we don't support yet
--    Base1             -- ^ unary (11111) ----- WTF?
--  | Base2             -- ^ binary (01010101)
--  | Base8             -- ^ octal
--  | Base10            -- ^ decimal

-- | Symbols for which a multibase code is defined and supported by this library
class ValidBase b => ToCode b where
    toCode   :: proxy b -> Char

instance ToCode "id" where
    toCode :: proxy "id" -> Char
toCode = Char -> proxy "id" -> Char
forall a b. a -> b -> a
const Char
'\000'
instance ToCode "16" where
    toCode :: proxy "16" -> Char
toCode = Char -> proxy "16" -> Char
forall a b. a -> b -> a
const Char
'f'
instance ToCode "16u" where
    toCode :: proxy "16u" -> Char
toCode = Char -> proxy "16u" -> Char
forall a b. a -> b -> a
const Char
'F'
instance ToCode "32x" where
    toCode :: proxy "32x" -> Char
toCode = Char -> proxy "32x" -> Char
forall a b. a -> b -> a
const Char
'v'
instance ToCode "32xu" where
    toCode :: proxy "32xu" -> Char
toCode = Char -> proxy "32xu" -> Char
forall a b. a -> b -> a
const Char
'V'
instance ToCode "32xp" where
    toCode :: proxy "32xp" -> Char
toCode = Char -> proxy "32xp" -> Char
forall a b. a -> b -> a
const Char
't'
instance ToCode "32xpu" where
    toCode :: proxy "32xpu" -> Char
toCode = Char -> proxy "32xpu" -> Char
forall a b. a -> b -> a
const Char
'T'
instance ToCode "32" where
    toCode :: proxy "32" -> Char
toCode = Char -> proxy "32" -> Char
forall a b. a -> b -> a
const Char
'b'
instance ToCode "32z" where
    toCode :: proxy "32z" -> Char
toCode = Char -> proxy "32z" -> Char
forall a b. a -> b -> a
const Char
'h'
instance ToCode "32u" where
    toCode :: proxy "32u" -> Char
toCode = Char -> proxy "32u" -> Char
forall a b. a -> b -> a
const Char
'B'
instance ToCode "32p" where
    toCode :: proxy "32p" -> Char
toCode  = Char -> proxy "32p" -> Char
forall a b. a -> b -> a
const Char
'c'
instance ToCode "32pu" where
    toCode :: proxy "32pu" -> Char
toCode  = Char -> proxy "32pu" -> Char
forall a b. a -> b -> a
const Char
'C'
instance ToCode "58flickr" where
    toCode :: proxy "58flickr" -> Char
toCode  = Char -> proxy "58flickr" -> Char
forall a b. a -> b -> a
const Char
'Z'
instance ToCode "58btc" where
    toCode :: proxy "58btc" -> Char
toCode  = Char -> proxy "58btc" -> Char
forall a b. a -> b -> a
const Char
'z'
instance ToCode "64" where
    toCode :: proxy "64" -> Char
toCode  = Char -> proxy "64" -> Char
forall a b. a -> b -> a
const Char
'm'
instance ToCode "64p" where
    toCode :: proxy "64p" -> Char
toCode  = Char -> proxy "64p" -> Char
forall a b. a -> b -> a
const Char
'M'
instance ToCode "64url" where
    toCode :: proxy "64url" -> Char
toCode  = Char -> proxy "64url" -> Char
forall a b. a -> b -> a
const Char
'u'
instance ToCode "64urlpad" where
    toCode :: proxy "64urlpad" -> Char
toCode  = Char -> proxy "64urlpad" -> Char
forall a b. a -> b -> a
const Char
'U'

-- codes we don't support yet
--toCode Base2             = '0'
--toCode Base8             = '7'
--toCode Base10            = '9'

fromCode :: Char -> Maybe (ByteString -> Either String ByteString)
fromCode :: Char -> Maybe (ByteString -> Either String ByteString)
fromCode Char
'\000' = (ByteString -> Either String ByteString)
-> Maybe (ByteString -> Either String ByteString)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ByteString -> Either String ByteString
forall (f :: * -> *) a. Applicative f => a -> f a
pure  -- 2 times pure, 2 times better!
fromCode Char
'f'    = (ByteString -> Either String ByteString)
-> Maybe (ByteString -> Either String ByteString)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Proxy "16" -> ByteString -> Either String ByteString
forall (b :: Symbol) (proxy :: Symbol -> *).
DecodeBase b =>
proxy b -> ByteString -> Either String ByteString
BaseN.decodeAtBaseEither (Proxy "16"
forall k (t :: k). Proxy t
Proxy @"16"))
fromCode Char
'F'    = (ByteString -> Either String ByteString)
-> Maybe (ByteString -> Either String ByteString)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Proxy "16u" -> ByteString -> Either String ByteString
forall (b :: Symbol) (proxy :: Symbol -> *).
DecodeBase b =>
proxy b -> ByteString -> Either String ByteString
BaseN.decodeAtBaseEither (Proxy "16u"
forall k (t :: k). Proxy t
Proxy @"16u"))
fromCode Char
'v'    = (ByteString -> Either String ByteString)
-> Maybe (ByteString -> Either String ByteString)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Proxy "32x" -> ByteString -> Either String ByteString
forall (b :: Symbol) (proxy :: Symbol -> *).
DecodeBase b =>
proxy b -> ByteString -> Either String ByteString
BaseN.decodeAtBaseEither (Proxy "32x"
forall k (t :: k). Proxy t
Proxy @"32x"))
fromCode Char
'V'    = (ByteString -> Either String ByteString)
-> Maybe (ByteString -> Either String ByteString)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Proxy "32xu" -> ByteString -> Either String ByteString
forall (b :: Symbol) (proxy :: Symbol -> *).
DecodeBase b =>
proxy b -> ByteString -> Either String ByteString
BaseN.decodeAtBaseEither (Proxy "32xu"
forall k (t :: k). Proxy t
Proxy @"32xu"))
fromCode Char
't'    = (ByteString -> Either String ByteString)
-> Maybe (ByteString -> Either String ByteString)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Proxy "32xp" -> ByteString -> Either String ByteString
forall (b :: Symbol) (proxy :: Symbol -> *).
DecodeBase b =>
proxy b -> ByteString -> Either String ByteString
BaseN.decodeAtBaseEither (Proxy "32xp"
forall k (t :: k). Proxy t
Proxy @"32xp"))
fromCode Char
'T'    = (ByteString -> Either String ByteString)
-> Maybe (ByteString -> Either String ByteString)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Proxy "32xpu" -> ByteString -> Either String ByteString
forall (b :: Symbol) (proxy :: Symbol -> *).
DecodeBase b =>
proxy b -> ByteString -> Either String ByteString
BaseN.decodeAtBaseEither (Proxy "32xpu"
forall k (t :: k). Proxy t
Proxy @"32xpu"))
fromCode Char
'b'    = (ByteString -> Either String ByteString)
-> Maybe (ByteString -> Either String ByteString)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Proxy "32" -> ByteString -> Either String ByteString
forall (b :: Symbol) (proxy :: Symbol -> *).
DecodeBase b =>
proxy b -> ByteString -> Either String ByteString
BaseN.decodeAtBaseEither (Proxy "32"
forall k (t :: k). Proxy t
Proxy @"32"))
fromCode Char
'h'    = (ByteString -> Either String ByteString)
-> Maybe (ByteString -> Either String ByteString)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Proxy "32z" -> ByteString -> Either String ByteString
forall (b :: Symbol) (proxy :: Symbol -> *).
DecodeBase b =>
proxy b -> ByteString -> Either String ByteString
BaseN.decodeAtBaseEither (Proxy "32z"
forall k (t :: k). Proxy t
Proxy @"32z"))
fromCode Char
'B'    = (ByteString -> Either String ByteString)
-> Maybe (ByteString -> Either String ByteString)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Proxy "32u" -> ByteString -> Either String ByteString
forall (b :: Symbol) (proxy :: Symbol -> *).
DecodeBase b =>
proxy b -> ByteString -> Either String ByteString
BaseN.decodeAtBaseEither (Proxy "32u"
forall k (t :: k). Proxy t
Proxy @"32u"))
fromCode Char
'c'    = (ByteString -> Either String ByteString)
-> Maybe (ByteString -> Either String ByteString)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Proxy "32p" -> ByteString -> Either String ByteString
forall (b :: Symbol) (proxy :: Symbol -> *).
DecodeBase b =>
proxy b -> ByteString -> Either String ByteString
BaseN.decodeAtBaseEither (Proxy "32p"
forall k (t :: k). Proxy t
Proxy @"32p"))
fromCode Char
'C'    = (ByteString -> Either String ByteString)
-> Maybe (ByteString -> Either String ByteString)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Proxy "32pu" -> ByteString -> Either String ByteString
forall (b :: Symbol) (proxy :: Symbol -> *).
DecodeBase b =>
proxy b -> ByteString -> Either String ByteString
BaseN.decodeAtBaseEither (Proxy "32pu"
forall k (t :: k). Proxy t
Proxy @"32pu"))
fromCode Char
'Z'    = (ByteString -> Either String ByteString)
-> Maybe (ByteString -> Either String ByteString)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Proxy "58flickr" -> ByteString -> Either String ByteString
forall (b :: Symbol) (proxy :: Symbol -> *).
DecodeBase b =>
proxy b -> ByteString -> Either String ByteString
BaseN.decodeAtBaseEither (Proxy "58flickr"
forall k (t :: k). Proxy t
Proxy @"58flickr"))
fromCode Char
'z'    = (ByteString -> Either String ByteString)
-> Maybe (ByteString -> Either String ByteString)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Proxy "58btc" -> ByteString -> Either String ByteString
forall (b :: Symbol) (proxy :: Symbol -> *).
DecodeBase b =>
proxy b -> ByteString -> Either String ByteString
BaseN.decodeAtBaseEither (Proxy "58btc"
forall k (t :: k). Proxy t
Proxy @"58btc"))
fromCode Char
'm'    = (ByteString -> Either String ByteString)
-> Maybe (ByteString -> Either String ByteString)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Proxy "64" -> ByteString -> Either String ByteString
forall (b :: Symbol) (proxy :: Symbol -> *).
DecodeBase b =>
proxy b -> ByteString -> Either String ByteString
BaseN.decodeAtBaseEither (Proxy "64"
forall k (t :: k). Proxy t
Proxy @"64"))
fromCode Char
'M'    = (ByteString -> Either String ByteString)
-> Maybe (ByteString -> Either String ByteString)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Proxy "64p" -> ByteString -> Either String ByteString
forall (b :: Symbol) (proxy :: Symbol -> *).
DecodeBase b =>
proxy b -> ByteString -> Either String ByteString
BaseN.decodeAtBaseEither (Proxy "64p"
forall k (t :: k). Proxy t
Proxy @"64p"))
fromCode Char
'u'    = (ByteString -> Either String ByteString)
-> Maybe (ByteString -> Either String ByteString)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Proxy "64url" -> ByteString -> Either String ByteString
forall (b :: Symbol) (proxy :: Symbol -> *).
DecodeBase b =>
proxy b -> ByteString -> Either String ByteString
BaseN.decodeAtBaseEither (Proxy "64url"
forall k (t :: k). Proxy t
Proxy @"64url"))
fromCode Char
'U'    = (ByteString -> Either String ByteString)
-> Maybe (ByteString -> Either String ByteString)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Proxy "64urlpad" -> ByteString -> Either String ByteString
forall (b :: Symbol) (proxy :: Symbol -> *).
DecodeBase b =>
proxy b -> ByteString -> Either String ByteString
BaseN.decodeAtBaseEither (Proxy "64urlpad"
forall k (t :: k). Proxy t
Proxy @"64urlpad"))
fromCode Char
_      = Maybe (ByteString -> Either String ByteString)
forall a. Maybe a
Nothing

-- | A multibase-encoded strict 'ByteString'.
newtype Multibase = Multibase ByteString
    deriving (Multibase -> Multibase -> Bool
(Multibase -> Multibase -> Bool)
-> (Multibase -> Multibase -> Bool) -> Eq Multibase
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Multibase -> Multibase -> Bool
$c/= :: Multibase -> Multibase -> Bool
== :: Multibase -> Multibase -> Bool
$c== :: Multibase -> Multibase -> Bool
Eq, Eq Multibase
Eq Multibase
-> (Multibase -> Multibase -> Ordering)
-> (Multibase -> Multibase -> Bool)
-> (Multibase -> Multibase -> Bool)
-> (Multibase -> Multibase -> Bool)
-> (Multibase -> Multibase -> Bool)
-> (Multibase -> Multibase -> Multibase)
-> (Multibase -> Multibase -> Multibase)
-> Ord Multibase
Multibase -> Multibase -> Bool
Multibase -> Multibase -> Ordering
Multibase -> Multibase -> Multibase
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
min :: Multibase -> Multibase -> Multibase
$cmin :: Multibase -> Multibase -> Multibase
max :: Multibase -> Multibase -> Multibase
$cmax :: Multibase -> Multibase -> Multibase
>= :: Multibase -> Multibase -> Bool
$c>= :: Multibase -> Multibase -> Bool
> :: Multibase -> Multibase -> Bool
$c> :: Multibase -> Multibase -> Bool
<= :: Multibase -> Multibase -> Bool
$c<= :: Multibase -> Multibase -> Bool
< :: Multibase -> Multibase -> Bool
$c< :: Multibase -> Multibase -> Bool
compare :: Multibase -> Multibase -> Ordering
$ccompare :: Multibase -> Multibase -> Ordering
$cp1Ord :: Eq Multibase
Ord, Int -> Multibase -> Int
Multibase -> Int
(Int -> Multibase -> Int)
-> (Multibase -> Int) -> Hashable Multibase
forall a. (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: Multibase -> Int
$chash :: Multibase -> Int
hashWithSalt :: Int -> Multibase -> Int
$chashWithSalt :: Int -> Multibase -> Int
Hashable, Multibase -> ()
(Multibase -> ()) -> NFData Multibase
forall a. (a -> ()) -> NFData a
rnf :: Multibase -> ()
$crnf :: Multibase -> ()
NFData)

-- | A 'Multibase backed by a 'ShortByteString'.
--
-- This is useful when holding many 'Multibase' values in memory, due to lower
-- memory overhead and less heap fragmentation. See the documentation for
-- 'ShortByteString' for details.
newtype CompactMultibase = Compact ShortByteString
    deriving (CompactMultibase -> CompactMultibase -> Bool
(CompactMultibase -> CompactMultibase -> Bool)
-> (CompactMultibase -> CompactMultibase -> Bool)
-> Eq CompactMultibase
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: CompactMultibase -> CompactMultibase -> Bool
$c/= :: CompactMultibase -> CompactMultibase -> Bool
== :: CompactMultibase -> CompactMultibase -> Bool
$c== :: CompactMultibase -> CompactMultibase -> Bool
Eq, Eq CompactMultibase
Eq CompactMultibase
-> (CompactMultibase -> CompactMultibase -> Ordering)
-> (CompactMultibase -> CompactMultibase -> Bool)
-> (CompactMultibase -> CompactMultibase -> Bool)
-> (CompactMultibase -> CompactMultibase -> Bool)
-> (CompactMultibase -> CompactMultibase -> Bool)
-> (CompactMultibase -> CompactMultibase -> CompactMultibase)
-> (CompactMultibase -> CompactMultibase -> CompactMultibase)
-> Ord CompactMultibase
CompactMultibase -> CompactMultibase -> Bool
CompactMultibase -> CompactMultibase -> Ordering
CompactMultibase -> CompactMultibase -> CompactMultibase
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
min :: CompactMultibase -> CompactMultibase -> CompactMultibase
$cmin :: CompactMultibase -> CompactMultibase -> CompactMultibase
max :: CompactMultibase -> CompactMultibase -> CompactMultibase
$cmax :: CompactMultibase -> CompactMultibase -> CompactMultibase
>= :: CompactMultibase -> CompactMultibase -> Bool
$c>= :: CompactMultibase -> CompactMultibase -> Bool
> :: CompactMultibase -> CompactMultibase -> Bool
$c> :: CompactMultibase -> CompactMultibase -> Bool
<= :: CompactMultibase -> CompactMultibase -> Bool
$c<= :: CompactMultibase -> CompactMultibase -> Bool
< :: CompactMultibase -> CompactMultibase -> Bool
$c< :: CompactMultibase -> CompactMultibase -> Bool
compare :: CompactMultibase -> CompactMultibase -> Ordering
$ccompare :: CompactMultibase -> CompactMultibase -> Ordering
$cp1Ord :: Eq CompactMultibase
Ord, Int -> CompactMultibase -> Int
CompactMultibase -> Int
(Int -> CompactMultibase -> Int)
-> (CompactMultibase -> Int) -> Hashable CompactMultibase
forall a. (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: CompactMultibase -> Int
$chash :: CompactMultibase -> Int
hashWithSalt :: Int -> CompactMultibase -> Int
$chashWithSalt :: Int -> CompactMultibase -> Int
Hashable, CompactMultibase -> ()
(CompactMultibase -> ()) -> NFData CompactMultibase
forall a. (a -> ()) -> NFData a
rnf :: CompactMultibase -> ()
$crnf :: CompactMultibase -> ()
NFData)

-- | Extract the encoded bytes, including the code 'Char', from a 'Multibase'.
fromMultibase :: Multibase -> ByteString
fromMultibase :: Multibase -> ByteString
fromMultibase = Multibase -> ByteString
coerce

-- | Extract the encoded bytes from a 'Multibase'.
--
-- The code 'Char' signifying the base is stripped.
encodedBytes :: Multibase -> ByteString
encodedBytes :: Multibase -> ByteString
encodedBytes = ByteString -> ByteString
C8.tail (ByteString -> ByteString)
-> (Multibase -> ByteString) -> Multibase -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Multibase -> ByteString
coerce

-- | Encode a strict 'ByteString' at 'Base'.
encode :: ToCode b => AtBase b -> Multibase
encode :: AtBase b -> Multibase
encode AtBase b
base = ByteString -> Multibase
coerce (ByteString -> Multibase)
-> (AtBase b -> ByteString) -> AtBase b -> Multibase
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> ByteString -> ByteString
C8.cons (AtBase b -> Char
forall (b :: Symbol) (proxy :: Symbol -> *).
ToCode b =>
proxy b -> Char
toCode AtBase b
base) (ByteString -> ByteString)
-> (AtBase b -> ByteString) -> AtBase b -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AtBase b -> ByteString
forall (b :: Symbol). AtBase b -> ByteString
BaseN.encodedBytes (AtBase b -> Multibase) -> AtBase b -> Multibase
forall a b. (a -> b) -> a -> b
$ AtBase b
base

-- | Decode a strict 'ByteString', assumed to be 'Multibase'-encoded.
decode :: ByteString -> Either String ByteString
decode :: ByteString -> Either String ByteString
decode ByteString
bs = do
    (Char
c, ByteString
bs') <- String
-> Maybe (Char, ByteString) -> Either String (Char, ByteString)
forall a b. a -> Maybe b -> Either a b
note String
"Empty input" (Maybe (Char, ByteString) -> Either String (Char, ByteString))
-> Maybe (Char, ByteString) -> Either String (Char, ByteString)
forall a b. (a -> b) -> a -> b
$ ByteString -> Maybe (Char, ByteString)
C8.uncons ByteString
bs
    case Char -> Maybe (ByteString -> Either String ByteString)
fromCode Char
c of
      Just ByteString -> Either String ByteString
decodeIt -> ByteString -> Either String ByteString
decodeIt ByteString
bs'
      Maybe (ByteString -> Either String ByteString)
Nothing       -> String -> Either String ByteString
forall a b. a -> Either a b
Left (String -> Either String ByteString)
-> String -> Either String ByteString
forall a b. (a -> b) -> a -> b
$ String
"Unknown encoding " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Char -> String
forall a. Show a => a -> String
show Char
c

-- | /O(n)/. Convert a 'Multibase' encoding to a compact representation.
--
-- Involves copying the underlying 'ByteString'.
compact :: Multibase -> CompactMultibase
compact :: Multibase -> CompactMultibase
compact = ShortByteString -> CompactMultibase
coerce (ShortByteString -> CompactMultibase)
-> (Multibase -> ShortByteString) -> Multibase -> CompactMultibase
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ShortByteString
toShort (ByteString -> ShortByteString)
-> (Multibase -> ByteString) -> Multibase -> ShortByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Multibase -> ByteString
coerce
{-# INLINE compact #-}

-- | /O(n)/. Convert from the compact to the regular representation.
--
-- Involves copying the underlying 'ShortByteString'.
expand :: CompactMultibase -> Multibase
expand :: CompactMultibase -> Multibase
expand = ByteString -> Multibase
coerce (ByteString -> Multibase)
-> (CompactMultibase -> ByteString)
-> CompactMultibase
-> Multibase
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShortByteString -> ByteString
fromShort (ShortByteString -> ByteString)
-> (CompactMultibase -> ShortByteString)
-> CompactMultibase
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CompactMultibase -> ShortByteString
coerce
{-# INLINE expand #-}

-- Helpers ---------------------------------------------------------------------

note :: a -> Maybe b -> Either a b
note :: a -> Maybe b -> Either a b
note a
a = Either a b -> (b -> Either a b) -> Maybe b -> Either a b
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (a -> Either a b
forall a b. a -> Either a b
Left a
a) b -> Either a b
forall (f :: * -> *) a. Applicative f => a -> f a
pure