packages feed

multidir-0.1.0.0: src/TOML/Decode/Extra.hs

{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TupleSections #-}

-- | Extra functionality for decoding TOML files
module TOML.Decode.Extra (
  decodeTableWith,
  decodeTableWithM,
  getTableOf,
  removeField,
  removeFieldOpt,
  removeFieldWith,
  removeFieldOptWith,
  processTableValuesWith,
  ) where

import Data.Map.Strict (Map)
import qualified Data.Map.Strict as M
import Data.Text (Text)
import TOML.Decode
import TOML.Error
import TOML.Value


pop :: Ord k => k -> Map k v -> (Maybe v, Map k v)
pop = M.alterF (,Nothing)

-- | We only want to process a table
decodeTableWithM :: (Table -> DecodeM a) -> Value -> DecodeM a
decodeTableWithM f = \case
  Table t -> f t
  v       -> typeMismatch v

-- | We only want to process a table
decodeTableWith :: (Table -> DecodeM a) -> Decoder a
decodeTableWith = Decoder . decodeTableWithM

-- Now moved upstream
getTableOf :: Decoder a -> Decoder (Map Text a)
getTableOf decoder =
  makeDecoder $ \case
    Table t -> M.traverseWithKey (\k -> addContextItem (Key k) . runDecoder decoder) t
    v -> typeMismatch v

-- | Remove a field, raising error if absent; return rest of table
removeFieldWith :: Decoder a -> Text -> Table -> DecodeM (Table, a)
removeFieldWith d k m = case pop k m of
  (Just v, m') -> (m',) <$> addContextItem (Key k) (unDecoder d v)
  (Nothing, _) -> DecodeM (Left . (, MissingField) . (<> [Key k]))

-- | Remove a field, signalling presence in Maybe; return rest of table
removeFieldOptWith :: Decoder a -> Text -> Table -> DecodeM (Table, Maybe a)
removeFieldOptWith d k m = case pop k m of
  (Just v,  m') -> (m',) . Just <$> addContextItem (Key k) (unDecoder d v)
  (Nothing, m') -> pure (m', Nothing)

-- | Remove a field, raising error if absent; return rest of table
removeField :: DecodeTOML a => Text -> Table -> DecodeM (Table, a)
removeField k m = case pop k m of
  (Just v, m') -> (m',) <$> addContextItem (Key k) (unDecoder tomlDecoder v)
  (Nothing, _) -> DecodeM (Left . (, MissingField) . (<> [Key k]))

-- | Remove a field, signalling presence in Maybe; return rest of table
removeFieldOpt :: DecodeTOML a => Text -> Table -> DecodeM (Table, Maybe a)
removeFieldOpt k m = case pop k m of
  (Just v,  m') -> (m',) . Just <$> addContextItem (Key k) (unDecoder tomlDecoder v)
  (Nothing, m') -> pure (m', Nothing)

-- | Run a decoder on the values of a table
processTableValuesWith :: Decoder a -> Table -> DecodeM (Map Text a)
processTableValuesWith d = M.traverseWithKey (\k -> addContextItem (Key k) . unDecoder d)