tricu

An interpreted language for exploring Tree Calculus
Log | Files | Refs | README | LICENSE

tasks.tri (5564B)


      1 !import http as Http
      2 !import native_math as N
      3 !import base as B
      4 !import io_v2 as IO
      5 !import handlers as H
      6 !export churnJoined
      7 !export churnDiscarded
      8 !export acknowledgedWrites
      9 !export partialWrites
     10 !export failedPartialWrite
     11 !export joined
     12 !export consumed
     13 !export supervised
     14 !export cancelled
     15 !export ordinary
     16 !export inherited
     17 !export changed
     18 !export callback
     19 !export labelledFailure
     20 !export labelledStateBoundary
     21 !export lazyLabels
     22 !export stateBoundary
     23 
     24 joinSpawn reply = case reply of
     25   ((t t), ([task ticket], t)) = IO.require (IO.join ticket) IO.pure
     26   _ = IO.fail "Invalid spawn reply"
     27 runChild action = IO.io <| IO.bind (IO.spawn 1 1 [] (_ : action)) joinSpawn
     28 joined = runChild (IO.pure 42)
     29 supervised = runChild (IO.fail "fault")
     30 cancelled = runChild (IO.cancelled "shutdown")
     31 ordinary = runChild (IO.pure (B.err "domain" t))
     32 consumed = IO.io <| IO.require (IO.spawn 1 1 [] (_ : IO.pure 42)) (spawned : case spawned of
     33   [task ticket] = do IO.bind
     34     first <- IO.join ticket
     35     second <- IO.join ticket
     36     IO.pure [first second]
     37   _ = IO.fail "Invalid spawn reply")
     38 
     39 value n _ _ = H.pure n
     40 child action = H.bind (H.spawnV2 1 1 [] (_ : action)) (reply : H.liftIO (joinSpawn reply))
     41 readValue = H.request "value" "get" t
     42 inherited = IO.io <| H.runIOV2 (H.handle "value" (value 7) (H.scopeV2 (owner : do H.bind
     43   answer <- child readValue
     44   parent <- readValue
     45   H.pure [answer parent])))
     46 changed = IO.io <| H.runIOV2 (H.handle "value" (value 7) (do H.bind
     47   answer <- child (H.handle "value" (value 9) readValue)
     48   parent <- readValue
     49   H.pure [answer parent]))
     50 spawner _ _ = child readValue
     51 callback = IO.io <| H.runIOV2 (H.handle "value" (value 7)
     52   (H.handle "spawn" spawner (H.handle "value" (value 9) (do H.bind
     53     answer <- H.request "spawn" "go" t
     54     parent <- readValue
     55     H.pure [answer parent]))))
     56 diverge x = diverge x
     57 lazyLabels seed = IO.io <| H.runIOV2 (H.label (diverge seed) (child (H.pure 7)))
     58 stateBoundary = runChild (H.runIOV2 (H.collect "log" "write" B.anyC t (child (H.pure 7))))
     59 
     60 -- Each child obtains a fresh host chunk. Constant/shared payloads would conceal
     61 -- a completion archive in an RSS-only test. Scope exit settles discarded work.
     62 churnStep mode reader = IO.scope (_ : IO.require
     63   (IO.spawn 0 1 [] (_ : IO.require (IO.readSome reader 4096) checkedChunk))
     64   (spawned : case spawned of
     65     [task ticket] = case mode of
     66       0 = IO.require (IO.join ticket) (_ : IO.pure t)
     67       _ = IO.require (IO.discard ticket) (_ : IO.pure t)
     68     _ = IO.fail "Invalid spawn reply"))
     69 churnLoop 0 _ _ = IO.pure t
     70 churnLoop count mode reader = IO.bind (churnStep mode reader)
     71   (_ : churnLoop (N.predecessor count) mode reader)
     72 churn mode count path = IO.io <| IO.scope (owner :
     73   IO.require (IO.openReader owner path) (reader : churnLoop count mode reader))
     74 churnJoined count path = churn 0 count path
     75 churnDiscarded count path = churn 1 count path
     76 
     77 checkedChunk ("data", bytes) = case Http.httpBodyLength bytes of
     78   4096 = IO.pure bytes
     79   _ = IO.fail "Incomplete retention input"
     80 checkedChunk _ = IO.fail "Unexpected retention EOF"
     81 
     82 labelledFailure = IO.io <| H.runIOV2 (H.label "outer"
     83   (child (H.label "inner" (H.fail "problem" "service" "op" "detail"))))
     84 labelledStateBoundary = runChild (H.runIOV2 (H.label "outer"
     85   (H.collect "log" "write" B.anyC t (H.label "inner" (child (H.pure 7))))))
     86 
     87 -- Test-only interpreter for the actual library convenience, not a reimplementation
     88 -- of its chunk dropping. Each successful mock accepts at most two bytes; fuel
     89 -- exhaustion fails before any further acceptance. Python specifies full traces.
     90 mockWrites fuel action frames accepted = let
     91   resume value = case frames of
     92     [] = [value accepted]
     93     [next | rest] = mockWrites fuel (next value) rest accepted
     94     _ = ["invalid frames"]
     95   in case action of
     96     (0, value) = resume value
     97     (1, (first, next)) = mockWrites fuel first (B.pair next frames) accepted
     98     (10, ("stream", (1, ("write", (writer, bytes))))) = case fuel of
     99       0 = resume (B.err "write fault" t)
    100       _ = case bytes of
    101         [a b | rest] = mockWrites (N.predecessor fuel) (IO.pure (B.ok 2 t)) frames
    102           (B.append accepted [a b])
    103         [a] = mockWrites (N.predecessor fuel) (IO.pure (B.ok 1 t)) frames
    104           (B.append accepted [a])
    105         _ = ["invalid chunk"]
    106     _ = ["invalid action"]
    107 partialWrites bytes = IO.io <| IO.pure (mockWrites 32 (IO.writeAll t bytes) [] [])
    108 failedPartialWrite bytes = IO.io <| IO.pure (mockWrites 1 (IO.writeAll t bytes) [] [])
    109 
    110 -- Caller-specified positive acknowledgements exercise full and partial chunks.
    111 -- Record actual submitted suffixes; Python checks them independently. Exhausted
    112 -- acknowledgements inject an uncertain operation failure before further progress.
    113 mockAcknowledgements counts action frames requests = let
    114   resume value = case frames of
    115     [] = [value (B.reverse requests)]
    116     [next | rest] = mockAcknowledgements counts (next value) rest requests
    117     _ = ["invalid frames"]
    118   in case action of
    119     (0, value) = resume value
    120     (1, (first, next)) = mockAcknowledgements counts first (B.pair next frames) requests
    121     (10, ("stream", (1, ("write", (writer, bytes))))) = case counts of
    122       [count | rest] = mockAcknowledgements rest (IO.pure (B.ok count t)) frames
    123         (B.pair bytes requests)
    124       [] = mockAcknowledgements [] (IO.pure (B.err "write fault" t)) frames
    125         (B.pair bytes requests)
    126       _ = ["invalid acknowledgements"]
    127     _ = ["invalid action"]
    128 acknowledgedWrites counts bytes =
    129   IO.io <| IO.pure (mockAcknowledgements counts (IO.writeAll t bytes) [] [])