git.iko.soy/rowtype-yoga/purescript-yoga-om-layer
on main help sign in
Split runScoped/withScoped, clean up where clauses
56fdc71Mark
spago.lock−6
@@ -14,9 +14,6 @@
14 {
14 {
15 "foldable-traversable": ">=6.0.0 <7.0.0"
15 "foldable-traversable": ">=6.0.0 <7.0.0"
16 },
16 },
17− {
18− "newtype": ">=5.0.0 <6.0.0"
19− },
20 {
17 {
21 "prelude": ">=6.0.2 <7.0.0"
18 "prelude": ">=6.0.2 <7.0.0"
22 },
19 },
@@ -26,9 +23,6 @@
26 {
23 {
27 "record-studio": ">=1.0.4 <2.0.0"
24 "record-studio": ">=1.0.4 <2.0.0"
28 },
25 },
29− {
30− "tuples": ">=7.0.0 <8.0.0"
31− },
32 {
26 {
33 "type-equality": ">=4.0.1 <5.0.0"
27 "type-equality": ">=4.0.1 <5.0.0"
34 },
28 },
spago.yaml−2
@@ -12,11 +12,9 @@ package:
12 - aff: ">=7.1.0 <8.0.0"
12 - aff: ">=7.1.0 <8.0.0"
13 - arrays: ">=7.3.0 <8.0.0"
13 - arrays: ">=7.3.0 <8.0.0"
14 - foldable-traversable: ">=6.0.0 <7.0.0"
14 - foldable-traversable: ">=6.0.0 <7.0.0"
15− - newtype: ">=5.0.0 <6.0.0"
16 - prelude: ">=6.0.2 <7.0.0"
15 - prelude: ">=6.0.2 <7.0.0"
17 - record: ">=4.0.0 <5.0.0"
16 - record: ">=4.0.0 <5.0.0"
18 - record-studio: ">=1.0.4 <2.0.0"
17 - record-studio: ">=1.0.4 <2.0.0"
19− - tuples: ">=7.0.0 <8.0.0"
20 - type-equality: ">=4.0.1 <5.0.0"
18 - type-equality: ">=4.0.1 <5.0.0"
21 - unsafe-coerce: ">=6.0.0 <7.0.0"
19 - unsafe-coerce: ">=6.0.0 <7.0.0"
22 - yoga-om: ">=1.2.2 <2.0.0"
20 - yoga-om: ">=1.2.2 <2.0.0"
src/Yoga/Om/Layer.purs+30−33
@@ -1,8 +1,8 @@
1-- @inline export makeLayer arity=1
1-- @inline export makeLayer arity=1
2-- @inline export runLayer arity=2
2-- @inline export runLayer arity=2
3module Yoga.Om.Layer
3module Yoga.Om.Layer
4− ( OmLayer(..)
4+ ( OmLayer
5− , Finalizers(..)
5+ , Finalizers
6 , makeLayer
6 , makeLayer
7 , makeScopedLayer
7 , makeScopedLayer
8 , bracketLayer
8 , bracketLayer
@@ -20,8 +20,6 @@ module Yoga.Om.Layer
20import Prelude
20import Prelude
21
21
22import Data.Array as Array
22import Data.Array as Array
23−import Data.Newtype (class Newtype)
24−import Data.Tuple.Nested ((/\), type (/\))
25import Data.Foldable (for_)
23import Data.Foldable (for_)
26import Effect.Aff (Aff, generalBracket)
24import Effect.Aff (Aff, generalBracket)
27import Effect.Aff.Class (liftAff)
25import Effect.Aff.Class (liftAff)
@@ -43,8 +41,6 @@ import Yoga.Om as Om
43-- | executed in reverse (LIFO) by `runScoped`.
41-- | executed in reverse (LIFO) by `runScoped`.
44newtype Finalizers = Finalizers (Array (Aff Unit))
42newtype Finalizers = Finalizers (Array (Aff Unit))
45
43
46−derive instance Newtype Finalizers _
47−
48instance Semigroup Finalizers where
44instance Semigroup Finalizers where
49 append (Finalizers a) (Finalizers b) = Finalizers (a <> b)
45 append (Finalizers a) (Finalizers b) = Finalizers (a <> b)
50
46
@@ -56,11 +52,11 @@ instance Monoid Finalizers where
56-- carries finalizers for resource cleanup
52-- carries finalizers for resource cleanup
57-- =============================================================================
53-- =============================================================================
58
54
55+type Built prov = { provisions :: Record prov, finalizers :: Finalizers }
56+
59-- | A layer that requires dependencies (req), provides services (prov),
57-- | A layer that requires dependencies (req), provides services (prov),
60-- | and may carry finalizers for scoped resource management.
58-- | and may carry finalizers for scoped resource management.
61−newtype OmLayer req prov err = OmLayer (Om (Record req) err (Record prov /\ Finalizers))
59+data OmLayer req prov err = OmLayer (Om (Record req) err (Built prov))
62−
63−derive instance Newtype (OmLayer req prov err) _
64
60
65-- =============================================================================
61-- =============================================================================
66-- Layer constructors
62-- Layer constructors
@@ -68,7 +64,7 @@ derive instance Newtype (OmLayer req prov err) _
68
64
69-- | Create a layer from an Om computation (no finalizers).
65-- | Create a layer from an Om computation (no finalizers).
70makeLayer :: forall req prov err. Om (Record req) err (Record prov) -> OmLayer req prov err
66makeLayer :: forall req prov err. Om (Record req) err (Record prov) -> OmLayer req prov err
71−makeLayer om = OmLayer (om <#> \r -> r /\ mempty)
67+makeLayer om = OmLayer (om <#> \provisions -> { provisions, finalizers: mempty })
72
68
73-- | Create a scoped layer with acquire/release semantics.
69-- | Create a scoped layer with acquire/release semantics.
74-- | The release function is guaranteed to run when `runScoped` closes the scope.
70-- | The release function is guaranteed to run when `runScoped` closes the scope.
@@ -78,10 +74,9 @@ makeScopedLayer
78 -> (Record prov -> Aff Unit)
74 -> (Record prov -> Aff Unit)
79 -> OmLayer req prov err
75 -> OmLayer req prov err
80makeScopedLayer acquire release = OmLayer do
76makeScopedLayer acquire release = OmLayer do
81− prov <- acquire
77+ provisions <- acquire
82− pure (prov /\ finalizer prov)
83− where
84− finalizer prov = Finalizers [ release prov ]
78+ let finalizers = Finalizers [ release provisions ]
79+ pure { provisions, finalizers }
85
80
86-- | Bracket-style scoped layer: acquire a resource, build provisions from it,
81-- | Bracket-style scoped layer: acquire a resource, build provisions from it,
87-- | and register a finalizer for the resource.
82-- | and register a finalizer for the resource.
@@ -93,10 +88,9 @@ bracketLayer
93 -> OmLayer req prov err
88 -> OmLayer req prov err
94bracketLayer acquire release use = OmLayer do
89bracketLayer acquire release use = OmLayer do
95 resource <- acquire
90 resource <- acquire
96− prov <- use resource
91+ provisions <- use resource
97− pure (prov /\ finalizer resource)
98− where
99− finalizer resource = Finalizers [ release resource ]
92+ let finalizers = Finalizers [ release resource ]
93+ pure { provisions, finalizers }
100
94
101-- =============================================================================
95-- =============================================================================
102-- Custom Type Errors for Missing Dependencies
96-- Custom Type Errors for Missing Dependencies
@@ -180,10 +174,10 @@ runLayer
180 => Record available
174 => Record available
181 -> OmLayer req prov err
175 -> OmLayer req prov err
182 -> Om (Record available) err (Record prov)
176 -> Om (Record available) err (Record prov)
183−runLayer _ctx layer = unsafeCastLayer layer <#> \(prov /\ _) -> prov
177+runLayer _ctx (OmLayer om) = widenCtx om <#> _.provisions
184 where
178 where
185− unsafeCastLayer :: OmLayer req prov err -> Om (Record available) err (Record prov /\ Finalizers)
179+ widenCtx :: Om (Record req) err (Built prov) -> Om (Record available) err (Built prov)
186− unsafeCastLayer = unsafeCoerce
180+ widenCtx = unsafeCoerce
187
181
188-- | Build a fully-provided layer, run finalizers, return the provisions.
182-- | Build a fully-provided layer, run finalizers, return the provisions.
189-- | Useful when you just need the built services.
183-- | Useful when you just need the built services.
@@ -204,13 +198,13 @@ withScoped
204withScoped (OmLayer om) callback = generalBracket acquire conditions use
198withScoped (OmLayer om) callback = generalBracket acquire conditions use
205 where
199 where
206 acquire = Om.runOm {} errorHandlers om
200 acquire = Om.runOm {} errorHandlers om
207− errorHandlers = { exception: \_ -> pure (unsafeCoerce {} /\ mempty) }
201+ errorHandlers = { exception: \_ -> pure { provisions: unsafeCoerce {}, finalizers: mempty } }
208 conditions =
202 conditions =
209− { completed: \_ (_ /\ fins) -> runFinalizers fins
203+ { completed: \_ built -> runFinalizers built.finalizers
210− , failed: \_ (_ /\ fins) -> runFinalizers fins
204+ , failed: \_ built -> runFinalizers built.finalizers
211− , killed: \_ (_ /\ fins) -> runFinalizers fins
205+ , killed: \_ built -> runFinalizers built.finalizers
212 }
206 }
213− use (prov /\ _) = callback prov
207+ use built = callback built.provisions
214
208
215-- | Run finalizers in reverse order (LIFO).
209-- | Run finalizers in reverse order (LIFO).
216runFinalizers :: Finalizers -> Aff Unit
210runFinalizers :: Finalizers -> Aff Unit
@@ -236,9 +230,11 @@ combineRequirements
236 -> OmLayer req2 prov2 err2
230 -> OmLayer req2 prov2 err2
237 -> OmLayer reqDeduped provMerged ()
231 -> OmLayer reqDeduped provMerged ()
238combineRequirements (OmLayer build1) (OmLayer build2) = OmLayer do
232combineRequirements (OmLayer build1) (OmLayer build2) = OmLayer do
239− prov1 /\ fins1 <- Om.expand build1
233+ built1 <- Om.expand build1
240− prov2 /\ fins2 <- Om.expand build2
234+ built2 <- Om.expand build2
241− pure (Record.merge prov1 prov2 /\ (fins1 <> fins2))
235+ let provisions = Record.merge built1.provisions built2.provisions
236+ let finalizers = built1.finalizers <> built2.finalizers
237+ pure { provisions, finalizers }
242
238
243-- =============================================================================
239-- =============================================================================
244-- Vertical composition — feed output of one layer into input of another
240-- Vertical composition — feed output of one layer into input of another
@@ -256,11 +252,12 @@ provide
256 -> OmLayer req prov1 err1
252 -> OmLayer req prov1 err1
257 -> OmLayer req prov2 ()
253 -> OmLayer req prov2 ()
258provide (OmLayer layer2) (OmLayer layer1) = OmLayer do
254provide (OmLayer layer2) (OmLayer layer1) = OmLayer do
259− prov1 /\ fins1 <- Om.expand layer1
255+ built1 <- Om.expand layer1
260− prov2 /\ fins2 <- runLayer2 prov1
256+ built2 <- runLayer2 built1.provisions
261− pure (prov2 /\ (fins1 <> fins2))
257+ let finalizers = built1.finalizers <> built2.finalizers
258+ pure { provisions: built2.provisions, finalizers }
262 where
259 where
263 runLayer2 ctx = liftAff $ Om.runOm ctx errorHandlers (Om.expand layer2)
260 runLayer2 ctx = liftAff $ Om.runOm ctx errorHandlers (Om.expand layer2)
264− errorHandlers = { exception: \_ -> pure (unsafeCoerce {} /\ mempty) }
261+ errorHandlers = { exception: \_ -> pure { provisions: unsafeCoerce {}, finalizers: mempty } }
265
262
266infixl 9 provide as >->
263infixl 9 provide as >->
test/Test/Main.purs+9−10
@@ -2,8 +2,6 @@ module Test.Main where
2
2
3import Prelude
3import Prelude
4
4
5−import Data.Newtype (un)
6−import Data.Tuple.Nested ((/\))
7import Effect (Effect)
5import Effect (Effect)
8import Effect.Aff (launchAff_, throwError, try)
6import Effect.Aff (launchAff_, throwError, try)
9import Effect.Aff.Class (liftAff)
7import Effect.Aff.Class (liftAff)
@@ -16,7 +14,7 @@ import Test.Spec.Assertions (shouldEqual)
16import Test.Spec.Reporter (consoleReporter)
14import Test.Spec.Reporter (consoleReporter)
17import Test.Spec.Runner (runSpec)
15import Test.Spec.Runner (runSpec)
18import Yoga.Om as Om
16import Yoga.Om as Om
19−import Yoga.Om.Layer (OmLayer(..), Finalizers, makeLayer, makeScopedLayer, bracketLayer, combineRequirements, runScoped, withScoped, provide)
17+import Yoga.Om.Layer (OmLayer, makeLayer, makeScopedLayer, bracketLayer, combineRequirements, runLayer, runScoped, withScoped, provide)
20
18
21-- Example types
19-- Example types
22type Config = { port :: Int, host :: String }
20type Config = { port :: Int, host :: String }
@@ -95,13 +93,14 @@ main = launchAff_ $ runSpec [ consoleReporter ] do
95
93
96 pure { logger, database }
94 pure { logger, database }
97
95
98− -- Run with the context
96+ let
97+ ctx =
98+ { config: { port: 5432, host: "localhost" }
99+ , accessLog: accessLog
100+ }
99− result /\ _ <- un OmLayer combinedLayer
101+ result <- runLayer ctx combinedLayer
100− # Om.runOm
102+ # Om.runOm ctx
101− { config: { port: 5432, host: "localhost" }
102− , accessLog: accessLog
103− }
104− { exception: \_ -> pure ({ logger: { log: \_ -> pure unit }, database: { query: \_ -> pure [] } } /\ (mempty :: Finalizers)) }
103+ { exception: \_ -> pure { logger: { log: \_ -> pure unit }, database: { query: \_ -> pure [] } } }
105
104
106 -- Check the access log
105 -- Check the access log
107 finalLog <- liftEffect $ Ref.read accessLog
106 finalLog <- liftEffect $ Ref.read accessLog