1 # Copied response completion data; successful host writes do not prove peer receipt. 2 import Base 3 4 type Outcome is Data: 5 HostAccepted{} 6 WriteFailed{code: U32, message: String} 7 IncompleteResponse{} 8 9 type Completion<-D: Data> is Data: 10 Completion{payload: D, status: U32, outcome: Outcome} 11 12 # Consumed inline while the admitted operation is still held. 13 # Supported receipts capture Data only through receipt's typed factory and a 14 # closed callback. Never hide affine dependencies in a disposable receipt. 15 type Receipt is Type: 16 Unobserved{} 17 Observed{send: U32 -> Outcome -> IO(Unit)} 18 19 def receipt.send(~D: Data, payload: D, +channel: Chan(Completion), status: U32, outcome: Outcome) -> IO(Unit): 20 do IO: 21 sent : Result<&1, &1, Completion, Unit> <- Chan.send(Completion, channel, Completion{payload, status, outcome}) 22 return Unit{} 23 24 def receipt(~D: Data, ~done: Completion -> IO(Unit), payload: D) -> Receipt: 25 Observed{status => outcome => done(Completion{payload, status, outcome})} 26 27 # The observer owns IO.join/explicit close, including when it receives later. 28 # Closing before reception is disposal; it never carries affine resources. 29 def open(~D: Data, payload: D) -> IO(Receipt & Chan(Completion)): 30 do IO)>: 31 +channel : Chan(Completion) <- Chan.new(Completion, 1) 32 return (Observed{status => outcome => receipt.send(~D, payload, channel, status, outcome)}, channel) 33 34 def report(receipt: Receipt, status: U32, outcome: Outcome) -> IO(Unit): 35 match receipt: 36 case Unobserved{}: 37 IO.pure(Unit, Unit{}) 38 case Observed{send}: 39 send(status, outcome) 40 41 # Explicit absence of a configured observer performs no logging or allocation. 42 def ignore(status: U32, outcome: Outcome) -> IO(Unit): 43 IO.pure(Unit, Unit{})