Skip to content

Commit 4765f45

Browse files
authored
Merge pull request #56 from serokell/worm2fed/ltb-65-buildable-for-configrec
[LTB-65] Add Buildable for ConfigRec
2 parents 39ff169 + b516300 commit 4765f45

File tree

10 files changed

+887
-714
lines changed

10 files changed

+887
-714
lines changed

.stylish-haskell.yaml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# SPDX-FileCopyrightText: 2021 Serokell <https://serokell.io>
2+
#
3+
# SPDX-License-Identifier: Unlicense
4+
5+
steps:
6+
- simple_align:
7+
cases: false
8+
top_level_patterns: false
9+
records: false
10+
- imports:
11+
align: none
12+
list_align: after_alias
13+
pad_module_names: false
14+
long_list_align: inline
15+
empty_list_align: inherit
16+
list_padding: 2
17+
separate_lists: true
18+
space_surround: false
19+
- trailing_whitespace: {}
20+
columns: 80
21+
newline: native
22+
language_extensions:
23+
- BangPatterns
24+
- ConstraintKinds
25+
- DataKinds
26+
- DefaultSignatures
27+
- DeriveDataTypeable
28+
- DeriveGeneric
29+
- DerivingStrategies
30+
- EmptyCase
31+
- ExistentialQuantification
32+
- ExplicitNamespaces
33+
- FlexibleContexts
34+
- FlexibleInstances
35+
- FunctionalDependencies
36+
- GADTs
37+
- GeneralizedNewtypeDeriving
38+
- LambdaCase
39+
- MultiParamTypeClasses
40+
- MultiWayIf
41+
- NamedFieldPuns
42+
- NoImplicitPrelude
43+
- OverloadedLabels
44+
- OverloadedStrings
45+
- PatternSynonyms
46+
- RecordWildCards
47+
- RecursiveDo
48+
- ScopedTypeVariables
49+
- StandaloneDeriving
50+
- TemplateHaskell
51+
- TupleSections
52+
- TypeApplications
53+
- TypeFamilies
54+
- TypeOperators
55+
- ViewPatterns

code/config/lib/Loot/Config.hs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,31 @@
11
{- SPDX-License-Identifier: MPL-2.0 -}
22

33
{-# LANGUAGE DataKinds #-}
4-
{-# LANGUAGE TypeOperators #-}
54

65
-- | Flexible and convenient configuration framework.
76
module Loot.Config
8-
( module Loot.Config.Record
9-
, module Loot.Config.Generics
10-
, module Loot.Config.Lens
11-
, module Loot.Config.CLI
7+
( module Loot.Config.Record
8+
, module Loot.Config.Generics
9+
, module Loot.Config.Lens
10+
, module Loot.Config.CLI
1211

13-
, Config
14-
, PartialConfig
12+
, Config
13+
, PartialConfig
1514

16-
, module Lens.Micro
17-
) where
15+
, module Lens.Micro
16+
) where
1817

1918
import Lens.Micro ((?~))
2019

20+
import Loot.Config.Buildable ()
2121
import Loot.Config.CLI
2222
import Loot.Config.Generics
2323
import Loot.Config.Lens
24-
import Loot.Config.Record ((::+), (::-), (:::), (::<), ConfigKind (Final, Partial), ConfigRec,
25-
branch, complement, finalise, finaliseDeferredUnsafe, option, selection,
26-
sub, tree, upcast)
24+
import Loot.Config.Record (ConfigKind (..), ConfigRec, branch, complement,
25+
finalise, finaliseDeferredUnsafe, option, selection,
26+
sub, tree, upcast, (::+), (::-), (:::), (::<))
2727
import Loot.Config.Yaml ()
2828

29-
3029
type Config = ConfigRec 'Final
3130

3231
type PartialConfig = ConfigRec 'Partial
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
{- SPDX-License-Identifier: MPL-2.0 -}
2+
3+
{-# OPTIONS_GHC -fno-warn-orphans #-}
4+
5+
{-# LANGUAGE DataKinds #-}
6+
{-# LANGUAGE KindSignatures #-}
7+
{-# LANGUAGE TypeOperators #-}
8+
{-# LANGUAGE UndecidableInstances #-}
9+
{-# LANGUAGE GADTs #-}
10+
11+
module Loot.Config.Buildable
12+
(
13+
) where
14+
15+
import Data.Vinyl (Rec (RNil, (:&)))
16+
import Fmt (Buildable (..), Builder, blockMapF)
17+
import GHC.TypeLits (KnownSymbol)
18+
19+
import Loot.Config.Record (ConfigKind, ConfigRec, Item (..), ItemKind,
20+
SumSelection, getConfigKey, (::+), (::-), (:::),
21+
(::<))
22+
23+
class OptionsToBuilderList (k :: ConfigKind) (is :: [ItemKind]) where
24+
configToBuilderList :: ConfigRec k is -> [(Text, Builder)]
25+
26+
instance OptionsToBuilderList (k :: ConfigKind) '[] where
27+
configToBuilderList RNil = []
28+
29+
undefinedBuilder :: Builder
30+
undefinedBuilder = build @Text "<undefined>"
31+
32+
instance
33+
( KnownSymbol l
34+
, Buildable v
35+
, OptionsToBuilderList k is
36+
) => OptionsToBuilderList k ((l ::: v) ': is)
37+
where
38+
configToBuilderList (itemOption :& rest) =
39+
let label = getConfigKey @l
40+
value = case itemOption of
41+
ItemOptionP (Just v) -> build v
42+
ItemOptionP Nothing -> undefinedBuilder
43+
ItemOptionF v -> build v
44+
in (label, value) : configToBuilderList @k @is rest
45+
46+
instance
47+
( KnownSymbol l
48+
, OptionsToBuilderList k us
49+
, OptionsToBuilderList k is
50+
) => OptionsToBuilderList k ((l ::< us) ': is)
51+
where
52+
configToBuilderList (ItemSub inner :& rest) =
53+
let label = getConfigKey @l
54+
value = blockMapF $ configToBuilderList inner
55+
in (label, value) : configToBuilderList rest
56+
57+
instance
58+
( KnownSymbol l
59+
, OptionsToBuilderList k (SumSelection l : us)
60+
, OptionsToBuilderList k is
61+
) => OptionsToBuilderList k ((l ::+ us) ': is)
62+
where
63+
configToBuilderList (itemSum :& rest) =
64+
let label = getConfigKey @l
65+
value = case itemSum of
66+
ItemSumP inner -> blockMapF $ configToBuilderList inner
67+
ItemSumF inner -> blockMapF $ configToBuilderList inner
68+
in (label, value) : configToBuilderList rest
69+
70+
instance
71+
( KnownSymbol l
72+
, OptionsToBuilderList k us
73+
, OptionsToBuilderList k is
74+
) => OptionsToBuilderList k ((l ::- us) ': is)
75+
where
76+
configToBuilderList (itemBranch :& rest) =
77+
let label = getConfigKey @l
78+
value = case itemBranch of
79+
ItemBranchP inner -> blockMapF $ configToBuilderList inner
80+
ItemBranchF (Just inner) -> blockMapF $ configToBuilderList inner
81+
ItemBranchF Nothing -> undefinedBuilder
82+
in (label, value) : configToBuilderList rest
83+
84+
instance OptionsToBuilderList k is => Buildable (ConfigRec k is) where
85+
build config = blockMapF $ configToBuilderList config

code/config/lib/Loot/Config/CLI.hs

Lines changed: 41 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,27 @@
66

77
-- | Utilities for reading configuration from command-line parameters.
88
module Loot.Config.CLI
9-
( ModParser
10-
, OptModParser
11-
, modifying
12-
, uplift
13-
, (..:)
14-
, (.%:)
15-
, (<*<)
16-
, (.::)
17-
, (%::)
18-
, (.:<)
19-
, (.:+)
20-
, (.:-)
21-
) where
22-
23-
import Data.Vinyl (Label, type (<:), rreplace, rcast)
9+
( ModParser
10+
, OptModParser
11+
, modifying
12+
, uplift
13+
, (..:)
14+
, (.%:)
15+
, (<*<)
16+
, (.::)
17+
, (%::)
18+
, (.:<)
19+
, (.:+)
20+
, (.:-)
21+
) where
22+
23+
import Data.Vinyl (Label, rcast, rreplace, type (<:))
2424
import Lens.Micro (ASetter')
2525
import Options.Applicative (Parser, optional)
2626

27-
import Loot.Config.Record (ConfigKind (Partial), ConfigRec, HasOption, HasSub,
28-
HasSum, HasBranch, SumSelection, option, sub, tree, branch)
27+
import Loot.Config.Record (ConfigKind (..), ConfigRec, HasBranch, HasOption,
28+
HasSub, HasSum, SumSelection, branch, option, sub,
29+
tree)
2930

3031
-- | Type for a parser which yields a modifier function instead of a
3132
-- value
@@ -92,56 +93,56 @@ type OptModParser cfg = ModParser (ConfigRec 'Partial cfg)
9293
-- | Combinator which declares a config parser which parses one config
9394
-- option, leaving other options empty.
9495
(.::)
95-
:: forall l is v. HasOption l is v
96-
=> Label l
97-
-> Parser v
98-
-> OptModParser is
96+
:: forall l is v. HasOption l is v
97+
=> Label l
98+
-> Parser v
99+
-> OptModParser is
99100
l .:: p = (\mv -> option l %~ (mv <|>)) <$> optional p
100101
infixr 6 .::
101102

102103
-- | Combinator which declares a config parser which modifies one config
103104
-- option, not touching other options.
104105
(%::)
105-
:: forall l is v. HasOption l is v
106-
=> Label l
107-
-> ModParser v
108-
-> OptModParser is
106+
:: forall l is v. HasOption l is v
107+
=> Label l
108+
-> ModParser v
109+
-> OptModParser is
109110
l %:: p = (\mf -> option l %~ fmap (fromMaybe id mf)) <$> optional p
110111
infixr 6 %::
111112

112113
-- | Combinator which declares a config parser which parses one
113114
-- subsection, leaving other options empty.
114115
(.:<)
115-
:: forall l is us. (HasSub l is us)
116-
=> Label l
117-
-> OptModParser us
118-
-> OptModParser is
116+
:: forall l is us. (HasSub l is us)
117+
=> Label l
118+
-> OptModParser us
119+
-> OptModParser is
119120
l .:< p = (\uf cfg -> cfg & sub l %~ uf) <$> p
120121
infixr 6 .:<
121122

122123
-- | Combinator which declares a config parser which parses one
123124
-- tree, leaving other options empty.
124125
(.:+)
125-
:: forall l is us ms. (HasSum l is ms, us ~ (SumSelection l : ms))
126-
=> Label l
127-
-> OptModParser us
128-
-> OptModParser is
126+
:: forall l is us ms. (HasSum l is ms, us ~ (SumSelection l : ms))
127+
=> Label l
128+
-> OptModParser us
129+
-> OptModParser is
129130
l .:+ p = (\uf cfg -> cfg & tree l %~ uf) <$> p
130131
infixr 6 .:+
131132

132133
-- | Combinator which declares a config parser which parses one
133134
-- branch, leaving other options empty.
134135
(.:-)
135-
:: forall l is us. (HasBranch l is us)
136-
=> Label l
137-
-> OptModParser us
138-
-> OptModParser is
136+
:: forall l is us. (HasBranch l is us)
137+
=> Label l
138+
-> OptModParser us
139+
-> OptModParser is
139140
l .:- p = (\uf cfg -> cfg & branch l %~ uf) <$> p
140141
infixr 6 .:-
141142

142143
-- | Lifts the modifier of a subconfig to a modifier of larger config.
143144
uplift
144-
:: forall is us. (is <: us)
145-
=> OptModParser is
146-
-> OptModParser us
145+
:: forall is us. (is <: us)
146+
=> OptModParser is
147+
-> OptModParser us
147148
uplift = fmap $ \f cfg -> rreplace (f $ rcast cfg) cfg

0 commit comments

Comments
 (0)