aboutsummaryrefslogtreecommitdiff
path: root/hsm-core
diff options
context:
space:
mode:
Diffstat (limited to 'hsm-core')
-rw-r--r--hsm-core/Hsm/Core/App.hs20
-rw-r--r--hsm-core/Hsm/Core/Bracket.hs24
-rw-r--r--hsm-core/Hsm/Core/Serial.hs43
-rw-r--r--hsm-core/hsm-core.cabal12
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