diff options
Diffstat (limited to 'hsm-core')
-rw-r--r-- | hsm-core/Hsm/Core/App.hs | 20 | ||||
-rw-r--r-- | hsm-core/Hsm/Core/Bracket.hs | 24 | ||||
-rw-r--r-- | hsm-core/Hsm/Core/Serial.hs | 43 | ||||
-rw-r--r-- | hsm-core/hsm-core.cabal | 12 |
4 files changed, 78 insertions, 21 deletions
diff --git a/hsm-core/Hsm/Core/App.hs b/hsm-core/Hsm/Core/App.hs new file mode 100644 index 0000000..88dabb2 --- /dev/null +++ b/hsm-core/Hsm/Core/App.hs @@ -0,0 +1,20 @@ +-- Provides combinators for bootstrapping applications with: +-- - Automated command-line parsing +-- - Help text generation +module Hsm.Core.App + ( bootstrapApp + , bootstrapAppNoEcho + ) +where + +import Data.Composition ((.:.)) +import Options.Applicative (Parser, execParser, fullDesc, helper, info, progDesc, (<**>)) +import System.IO.Echo (withoutInputEcho) + +-- Launches a console application with input echo enabled +bootstrapApp :: Parser o -> String -> (o -> IO a) -> IO a +bootstrapApp parser desc app = execParser (info (parser <**> helper) $ fullDesc <> progDesc desc) >>= app + +-- Launches an application with hidden input echo +bootstrapAppNoEcho :: Parser o -> String -> (o -> IO a) -> IO a +bootstrapAppNoEcho = withoutInputEcho .:. bootstrapApp diff --git a/hsm-core/Hsm/Core/Bracket.hs b/hsm-core/Hsm/Core/Bracket.hs new file mode 100644 index 0000000..92428de --- /dev/null +++ b/hsm-core/Hsm/Core/Bracket.hs @@ -0,0 +1,24 @@ +-- Resource management combinators for safe acquisition/release patterns. +-- Provides specialized bracket variants for common scenarios. +module Hsm.Core.Bracket + ( bracketConst + , bracketCont + , bracketLiftIO_ + ) +where + +import Control.Monad.Trans.Cont (Cont, cont) +import Effectful (Eff, IOE, liftIO, (:>)) +import Effectful.Exception (bracket, bracket_) + +-- Ignores allocated resource in the action +bracketConst :: Eff es a -> (a -> Eff es b) -> Eff es c -> Eff es c +bracketConst alloc dealloc = bracket alloc dealloc . const + +-- Continuation-passing style integration +bracketCont :: Eff es a -> (a -> Eff es b) -> Cont (Eff es c) a +bracketCont alloc dealloc = cont $ bracket alloc dealloc + +-- Lifts IO operations into Effectful brackets +bracketLiftIO_ :: IOE :> es => IO a -> IO b -> Eff es c -> Eff es c +bracketLiftIO_ alloc dealloc = bracket_ (liftIO alloc) $ liftIO dealloc diff --git a/hsm-core/Hsm/Core/Serial.hs b/hsm-core/Hsm/Core/Serial.hs index a0efca3..7c607ff 100644 --- a/hsm-core/Hsm/Core/Serial.hs +++ b/hsm-core/Hsm/Core/Serial.hs @@ -2,21 +2,22 @@ module Hsm.Core.Serial ( makeSerial - ) where + ) +where import GHC.Num (integerFromInt) import Language.Haskell.TH - ( Body(NormalB) - , Clause(Clause) - , Con(NormalC) - , Dec(DataD, FunD, SigD) - , DerivClause(DerivClause) - , Exp(LitE) - , Lit(IntegerL) + ( Body (NormalB) + , Clause (Clause) + , Con (NormalC) + , Dec (DataD, FunD, SigD) + , DerivClause (DerivClause) + , Exp (LitE) + , Lit (IntegerL) , Name - , Pat(ConP) + , Pat (ConP) , Q - , Type(AppT, ArrowT, ConT) + , Type (AppT, ArrowT, ConT) , mkName ) @@ -36,13 +37,17 @@ import Language.Haskell.TH -- Generates a data type `GPIOPin` with constructors `GPIO2`, `GPIO3` `GPIO4`, -- and a function `pinLine :: GPIOPin -> Int`. makeSerial :: String -> String -> String -> Name -> [Int] -> Q [Dec] -makeSerial name suffix mapFun mapType idxs = - return [DataD [] dtName [] Nothing (idxCons <$> idxs) [derivClause], SigD mapFunName . AppT (AppT ArrowT $ ConT dtName) $ ConT mapType, FunD mapFunName $ mapFunClause <$> idxs] +makeSerial name suffix mapFunction mapType indices = + return + [ DataD [] dataName [] Nothing (indexCons <$> indices) [deriveClause] + , SigD mapFunctionName $ ArrowT `AppT` ConT dataName `AppT` ConT mapType + , FunD mapFunctionName $ mapFunctionClause <$> indices + ] where - dtName = mkName $ name <> suffix - idxName idx = mkName $ name <> show idx - idxCons idx = NormalC (idxName idx) [] - derivClause = DerivClause Nothing [ConT ''Bounded, ConT ''Enum, ConT ''Show] - mapFunName = mkName mapFun - mapFunBody = NormalB . LitE . IntegerL . integerFromInt - mapFunClause idx = Clause [ConP (idxName idx) [] []] (mapFunBody idx) [] + dataName = mkName $ name <> suffix + indexName index = mkName $ name <> show index + indexCons index = NormalC (indexName index) [] + deriveClause = DerivClause Nothing [ConT ''Bounded, ConT ''Enum, ConT ''Show] + mapFunctionName = mkName mapFunction + mapFunctionBody = NormalB . LitE . IntegerL . integerFromInt + mapFunctionClause index = Clause [ConP (indexName index) [] []] (mapFunctionBody index) [] diff --git a/hsm-core/hsm-core.cabal b/hsm-core/hsm-core.cabal index 856a359..6a0efff 100644 --- a/hsm-core/hsm-core.cabal +++ b/hsm-core/hsm-core.cabal @@ -3,12 +3,20 @@ author: Paul Oliver <contact@pauloliver.dev> name: hsm-core version: 0.1.0.0 - library build-depends: , base + , composition + , echo + , effectful-core + , optparse-applicative , template-haskell + , transformers default-language: GHC2024 - exposed-modules: Hsm.Core.Serial + exposed-modules: + Hsm.Core.App + Hsm.Core.Bracket + Hsm.Core.Serial + ghc-options: -O2 -Wall -Werror -Wno-star-is-type -Wunused-packages |