module Data.SerializableBlob
  ( SerializableBlob,
    fromText,
    fromBS,
    fromLBS,
    toLBS,
  )
where

import Data.Aeson qualified as J
import Data.ByteString qualified as B
import Data.ByteString.Base64 qualified as B64
import Data.ByteString.Lazy qualified as BL
import Data.String
import Data.Text qualified as T
import Data.Text.Encoding qualified as TE
import Prelude

-- | A JSON-serializable type for either text or raw binary data, encoded with base-64.
data SerializableBlob
  = SerializableText T.Text
  | SerializableBytes B.ByteString
  deriving (Int -> SerializableBlob -> ShowS
[SerializableBlob] -> ShowS
SerializableBlob -> String
(Int -> SerializableBlob -> ShowS)
-> (SerializableBlob -> String)
-> ([SerializableBlob] -> ShowS)
-> Show SerializableBlob
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SerializableBlob] -> ShowS
$cshowList :: [SerializableBlob] -> ShowS
show :: SerializableBlob -> String
$cshow :: SerializableBlob -> String
showsPrec :: Int -> SerializableBlob -> ShowS
$cshowsPrec :: Int -> SerializableBlob -> ShowS
Show)

instance J.ToJSON SerializableBlob where
  toJSON :: SerializableBlob -> Value
toJSON (SerializableText Text
t) =
    Text -> Value
forall a. ToJSON a => a -> Value
J.toJSON Text
t
  toJSON (SerializableBytes ByteString
bs) =
    -- try and turn into utf-8
    case ByteString -> Either UnicodeException Text
TE.decodeUtf8' ByteString
bs of
      -- if it's valid utf-8, treat it like the Text case
      Right Text
t -> Text -> Value
forall a. ToJSON a => a -> Value
J.toJSON Text
t
      -- otherwise base-64 encode it instead
      Left UnicodeException
_ -> [Text] -> Value
forall a. ToJSON a => a -> Value
J.toJSON [Text
"Base64", ByteString -> Text
TE.decodeUtf8 (ByteString -> ByteString
B64.encode ByteString
bs)]

instance IsString SerializableBlob where
  fromString :: String -> SerializableBlob
fromString = Text -> SerializableBlob
fromText (Text -> SerializableBlob)
-> (String -> Text) -> String -> SerializableBlob
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack

fromText :: T.Text -> SerializableBlob
fromText :: Text -> SerializableBlob
fromText = Text -> SerializableBlob
SerializableText

fromBS :: B.ByteString -> SerializableBlob
fromBS :: ByteString -> SerializableBlob
fromBS = ByteString -> SerializableBlob
SerializableBytes

fromLBS :: BL.ByteString -> SerializableBlob
fromLBS :: ByteString -> SerializableBlob
fromLBS =
  ByteString -> SerializableBlob
fromBS (ByteString -> SerializableBlob)
-> (ByteString -> ByteString) -> ByteString -> SerializableBlob
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
BL.toStrict

toBS :: SerializableBlob -> B.ByteString
toBS :: SerializableBlob -> ByteString
toBS (SerializableBytes ByteString
bs) = ByteString
bs
toBS (SerializableText Text
t) = Text -> ByteString
TE.encodeUtf8 Text
t

toLBS :: SerializableBlob -> BL.ByteString
toLBS :: SerializableBlob -> ByteString
toLBS = ByteString -> ByteString
BL.fromStrict (ByteString -> ByteString)
-> (SerializableBlob -> ByteString)
-> SerializableBlob
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SerializableBlob -> ByteString
toBS