Skip to content

Commit

Permalink
Provide mapOf and listOf
Browse files Browse the repository at this point in the history
  • Loading branch information
glguy committed Feb 21, 2024
1 parent cc57969 commit 9b026e5
Show file tree
Hide file tree
Showing 10 changed files with 57 additions and 51 deletions.
4 changes: 4 additions & 0 deletions src/Toml/Schema.hs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ Maintainer : emertens@gmail.com
module Toml.Schema (
-- * FromValue
FromValue(..),
mapOf,
listOf,

-- ** Matcher
Matcher,
Expand Down Expand Up @@ -64,5 +66,7 @@ module Toml.Schema (

import Toml.Schema.FromValue
import Toml.Schema.Generic
import Toml.Schema.ParseTable
import Toml.Schema.Matcher
import Toml.Schema.ToValue
import Toml.Semantics
76 changes: 39 additions & 37 deletions src/Toml/Schema/FromValue.hs
Original file line number Diff line number Diff line change
Expand Up @@ -27,37 +27,17 @@ module Toml.Schema.FromValue (
FromValue(..),
FromKey(..),

-- * Matcher
runMatcher,
runMatcherFatalWarn,
runMatcherIgnoreWarn,
Matcher,
MatchMessage(..),
Result(..),
warn,
warnAt,
failAt,

-- * Table matching
ParseTable,
parseTable,
-- * Containers
mapOf,
listOf,

-- * Tables
parseTableFromValue,
reqKey,
optKey,
reqKeyOf,
optKey,
optKeyOf,
warnTable,
warnTableAt,
failTableAt,
KeyAlt(..),
pickKey,
getScope,
Scope(..),

-- * Table matching primitives
getTable,
setTable,
liftMatcher,

) where

import Control.Monad (zipWithM)
Expand All @@ -79,21 +59,43 @@ import Toml.Schema.Matcher
import Toml.Schema.ParseTable
import Toml.Semantics

-- | Table matching function used to help implement 'fromValue' for tables.
-- Key matching function is given the annotation of the key for error reporting.
-- Value matching function is given the key in case values can depend on their keys.
mapOf ::
Ord k =>
(l -> Text -> Matcher l k) {- ^ key matcher -} ->
(Text -> Value' l -> Matcher l v) {- ^ value matcher -} ->
Value' l -> Matcher l (Map k v)
mapOf matchKey matchVal =
\case
Table' _ (MkTable t) -> Map.fromList <$> sequence kvs
where
kvs = [liftA2 (,) (matchKey l k) (inKey k (matchVal k v)) | (k, (l, v)) <- Map.assocs t]
v -> typeError "table" v

-- | List matching function used to help implemented 'fromValue' for arrays.
-- The element matching function is given the list index in case values can
-- depend on their index.
listOf ::
(Int -> Value' l -> Matcher l a) ->
Value' l -> Matcher l [a]
listOf matchElt =
\case
List' _ xs -> zipWithM (\i -> inIndex i . matchElt i) [0..] xs
v -> typeError "array" v

-- | Class for types that can be decoded from a TOML value.
class FromValue a where
-- | Convert a 'Value' or report an error message
fromValue :: Value' l -> Matcher l a

-- | Used to implement instance for @[]@. Most implementations rely on the default implementation.
listFromValue :: Value' l -> Matcher l [a]
listFromValue (List' _ xs) = zipWithM (\i v -> inIndex i (fromValue v)) [0..] xs
listFromValue v = typeError "array" v
listFromValue = listOf (const fromValue)

instance (Ord k, FromKey k, FromValue v) => FromValue (Map k v) where
fromValue (Table' _ (MkTable t)) = Map.fromList <$> traverse f (Map.assocs t)
where
f (k,(_, v)) = (,) <$> fromKey k <*> inKey k (fromValue v)
fromValue v = typeError "table" v
fromValue = mapOf fromKey (const fromValue)

instance FromValue Table where
fromValue (Table' _ t) = pure (forgetTableAnns t)
Expand All @@ -103,25 +105,25 @@ instance FromValue Table where
--
-- @since 1.3.0.0
class FromKey a where
fromKey :: Text -> Matcher l a
fromKey :: l -> Text -> Matcher l a

-- | Matches all strings
--
-- @since 1.3.0.0
instance a ~ Char => FromKey [a] where
fromKey = pure . Text.unpack
fromKey _ = pure . Text.unpack

-- | Matches all strings
--
-- @since 1.3.0.0
instance FromKey Text where
fromKey = pure
fromKey _ = pure

-- | Matches all strings
--
-- @since 1.3.0.0
instance FromKey Data.Text.Lazy.Text where
fromKey = pure . Data.Text.Lazy.fromStrict
fromKey _ = pure . Data.Text.Lazy.fromStrict

-- | Report a type error
typeError :: String {- ^ expected type -} -> Value' l {- ^ actual value -} -> Matcher l a
Expand Down
3 changes: 2 additions & 1 deletion src/Toml/Schema/Generic.hs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ module Toml.Schema.Generic (
genericFromArray,
genericFromTable,
GFromArray,
GToArray,
GParseTable,

-- * ToValue
genericToArray,
Expand All @@ -53,6 +53,7 @@ module Toml.Schema.Generic (
import Data.Coerce (coerce)
import GHC.Generics (Generic(Rep))
import Toml.Schema.FromValue
import Toml.Schema.Matcher
import Toml.Schema.Generic.FromValue
import Toml.Schema.Generic.ToValue (GToTable, GToArray, genericToTable, genericToArray)
import Toml.Schema.ToValue (ToTable(toTable), ToValue(toValue), defaultTableToValue)
Expand Down
2 changes: 1 addition & 1 deletion test/DecodeSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import Data.Maybe (fromMaybe)
import GHC.Generics (Generic)
import QuoteStr (quoteStr)
import Test.Hspec (it, shouldBe, Spec)
import Toml
import Toml (decode, encode)
import Toml.Schema

newtype Fruits = Fruits { fruits :: [Fruit] }
Expand Down
1 change: 0 additions & 1 deletion test/DerivingViaSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ module DerivingViaSpec (spec) where

import GHC.Generics (Generic)
import Test.Hspec (it, shouldBe, Spec)
import Toml
import Toml.Schema

data Physical = Physical {
Expand Down
4 changes: 2 additions & 2 deletions test/HieDemoSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import Data.Text (Text)
import GHC.Generics ( Generic )
import QuoteStr (quoteStr)
import Test.Hspec (Spec, it, shouldBe)
import Toml (decode, Value'(..), Table')
import Toml.Schema
import Toml (decode)
import Toml.Schema as Toml

-----------------------------------------------------------------------
-- THIS CODE DERIVED FROM CODE UNDER THE FOLLOWING LICENSE
Expand Down
4 changes: 2 additions & 2 deletions test/LexerSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
module LexerSpec (spec) where

import Test.Hspec (it, shouldBe, Spec)
import Toml
import Toml.Schema
import Toml (Value'(Integer), parse)
import Toml.Schema (table, (.=))

spec :: Spec
spec =
Expand Down
6 changes: 3 additions & 3 deletions test/PrettySpec.hs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{-# Language OverloadedStrings #-}
module PrettySpec (spec) where

import Test.Hspec (it, shouldBe, Spec)
import QuoteStr (quoteStr)
import Toml (encode, parse, prettyToml, Table)
import Data.Map qualified as Map
import Data.Text (Text)
import QuoteStr (quoteStr)
import Test.Hspec (it, shouldBe, Spec)
import Toml (encode, parse, prettyToml, Table)

tomlString :: Table -> String
tomlString = show . prettyToml
Expand Down
4 changes: 2 additions & 2 deletions test/ToValueSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
module ToValueSpec where

import Test.Hspec (it, shouldBe, Spec)
import Toml
import Toml.Schema
import Toml (Value'(Integer, Text, List))
import Toml.Schema (ToValue(toValue))

spec :: Spec
spec =
Expand Down
4 changes: 2 additions & 2 deletions test/TomlSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import Data.Text (Text)
import Data.Time (Day)
import QuoteStr (quoteStr)
import Test.Hspec (describe, it, shouldBe, shouldSatisfy, Spec)
import Toml
import Toml.Schema
import Toml (Result(..), Table'(..), Value'(..), parse, decode)
import Toml.Schema (table, (.=))

spec :: Spec
spec =
Expand Down

0 comments on commit 9b026e5

Please sign in to comment.