packages feed

rio-app-0.1.0.0: example/Main.hs

{-# LANGUAGE ApplicativeDo #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}

module Main (main) where

import RIO
import Data.Char (chr, ord)
import RIO.State (modify)
import Control.Monad.Trans.Resource (register, release)

import Data.Acquire
import RIO.App
import Options.Applicative.Simple (simpleVersion, simpleOptions)
import qualified Options.Applicative.Simple as Opt

import qualified Paths_rio_app

main :: IO ()
main = appMain parseOptions optionsVerbose setup run

setup :: Options -> RIO SetupApp (Char, Int)
setup opts = do
  -- XXX: Setup has logging, but no special env and state
  logDebug $ displayShow opts
  () <- asks appEnv
  modify $ \() -> ()

  {- XXX:
    Setup has resources that are acquired for the application lifetime
    and released in reverse order.
  -}
  (_releaseKey, res) <- allocateAcquire $ scarceResource 0
  register $
    hPutBuilder stderr "Bye!\n"

  pure (res, 0)

-- TODO: lift acquire procedures to allow logging etc.
scarceResource :: Int -> Acquire Char
scarceResource n =
  mkAcquire create destroy
  where
    create = do
      let r = chr (ord 'R' + n)
      hPutBuilder stderr . getUtf8Builder $
        "Resource created: " <> displayShow r <> "\n"
      pure r

    destroy res =
      hPutBuilder stderr . getUtf8Builder $
        "Destroying resource: " <> displayShow res <> "\n"

run :: RIO (App Char Int) ()
run = do
  modify (+ 1)
  logInfo "We're inside the application!"
  nestApp
    ((,) <$> asks appEnv <*> pure ())
    runInner

runInner :: RIO (App Char st) ()
runInner = do
  (releaseKey, res) <- allocateAcquire $ scarceResource 2
  logInfo "We're inside even more!"
  release releaseKey
  logInfo $ "  Our resource was: " <> displayShow res

-- | Command line arguments
data Options = Options
  { optionsVerbose :: Bool
  }
  deriving (Show)

parseOptions :: IO Options
parseOptions = do
  (options, ()) <- simpleOptions
    $(simpleVersion Paths_rio_app.version)
    header
    description
    optionsP
    commandP
  pure options
  where
    header =
      "Header for command line arguments"

    description =
      "Program description, also for command line arguments"

    optionsP = do
      optionsVerbose <- Opt.switch $ mconcat
        [ Opt.long "verbose"
        , Opt.short 'v'
        , Opt.help "Show more and more detailed messages"
        ]

      pure Options{..}

    commandP =
      Opt.empty