dap-0.1.0.0: src/DAP/Utils.hs
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
----------------------------------------------------------------------------
-- |
-- Module : DAP.Utils
-- Copyright : (C) 2023 David M. Johnson
-- License : BSD3-style (see the file LICENSE)
-- Stability : experimental
-- Portability : non-portable
----------------------------------------------------------------------------
module DAP.Utils where
----------------------------------------------------------------------------
import GHC.Generics (Generic, Rep)
import Data.Aeson ( ToJSON, Value, fieldLabelModifier
, genericToJSON, genericParseJSON, fieldLabelModifier
, defaultOptions, GToJSON, GFromJSON, Zero
, constructorTagModifier, sumEncoding
, SumEncoding(UntaggedValue), omitNothingFields
)
import Data.Aeson.Types ( Parser )
import Data.Aeson.Encode.Pretty ( encodePretty )
import Data.ByteString ( ByteString )
import Data.Char ( isLower, toLower, toUpper )
import Data.Proxy (Proxy(Proxy))
import Data.Typeable ( Typeable, typeRep )
import qualified Data.ByteString.Lazy.Char8 as BL8
import qualified Data.ByteString.Char8 as BS
----------------------------------------------------------------------------
-- | Encodes DAP protocol message appropriately
-- >
encodeBaseProtocolMessage :: ToJSON a => a -> ByteString
encodeBaseProtocolMessage msg =
mconcat
[ "Content-Length: " <> BS.pack (show (BS.length bytes)) <> "\r\n\r\n"
, bytes
] where
bytes = BL8.toStrict (encodePretty msg)
----------------------------------------------------------------------------
-- | Capitalization helper function
-- >>> capitalize "fooBar"
-- >>> "FooBar"
capitalize :: String -> String
capitalize [] = []
capitalize (x:xs)
| isLower x = toUpper x : xs
| otherwise = x : xs
----------------------------------------------------------------------------
-- | Lower cases a word
-- >>> toLowerCase "FooBar"
-- >>> "fooBar"
toLowerCase :: String -> String
toLowerCase [] = []
toLowerCase (x:xs) = toLower x : xs
----------------------------------------------------------------------------
-- | Used as a fieldLabelModifier when generating aeson parsers
-- >>> modifier (Proxy @Int) "intThing"
-- >>> String "thing"
modifier
:: Typeable a
=> proxy a
-> String
-> String
modifier proxy
= toLowerCase
. drop (length (getName proxy))
----------------------------------------------------------------------------
-- | Used as a fieldLabelModifier when generating aeson parsers
-- >>> getName (Proxy @Int)
-- >>> "Int"
getName
:: Typeable a
=> proxy a
-> String
getName proxy = show (typeRep proxy)
----------------------------------------------------------------------------
-- | Used as a fieldLabelModifier when generating aeson parsers
-- >>> getName (Proxy @Int)
-- >>> "Int"
genericToJSONWithModifier
:: forall a . (Generic a, GToJSON Zero (Rep a), Typeable a)
=> a -> Value
genericToJSONWithModifier
= genericToJSON defaultOptions
{ fieldLabelModifier = modifier (Proxy @a)
, constructorTagModifier = modifier (Proxy @a)
, sumEncoding = UntaggedValue
, omitNothingFields = True
}
----------------------------------------------------------------------------
-- | Used as a fieldLabelModifier when generating aeson parsers
-- >>> getName (Proxy @Int)
-- >>> "Int"
genericParseJSONWithModifier
:: forall a . (Generic a, GFromJSON Zero (Rep a), Typeable a)
=> Value
-> Parser a
genericParseJSONWithModifier
= genericParseJSON defaultOptions
{ fieldLabelModifier = modifier (Proxy @a)
, constructorTagModifier = modifier (Proxy @a)
, sumEncoding = UntaggedValue
, omitNothingFields = True
}
----------------------------------------------------------------------------
-- | Log formatting util
withBraces :: BL8.ByteString -> BL8.ByteString
withBraces x = "[" <> x <> "]"
----------------------------------------------------------------------------