1 # ezsys/src/step: every decision the file and environment helpers make. It 2 # does no IO; src/sys.bend runs the effects and acts on these answers 3 # (SYS-TRUST-4). 4 import Base 5 6 # after one read: read again with the text so far, or stop with an answer 7 type Read is Type: 8 ReadMore{text: String} 9 ReadStop{answer: Result<&1, &1, U32 & String, String>} 10 11 # after the temporary file is written: rename it, or stop with a failure 12 type Save is Type: 13 SaveMove{} 14 SaveStop{error: U32 & String} 15 16 # the bytes one read asks for: the file's size, and at least 64 KiB 17 def read.chunk(size: U32) -> U32: 18 U32.max(size, 65536) 19 20 # a chunk that is empty ends the file; any other is appended 21 def read.more(empty: Bool, text: String, got: String) -> Read: 22 match empty: 23 case True{}: 24 ReadStop{Done{got}} 25 case False{}: 26 ReadMore{got ++ text} 27 28 # what one read's answer means, with the text read before it 29 def read.step(res: Result<&1, &1, U32 & String, String>, got: String) -> Read: 30 match res: 31 case Fail{error}: 32 ReadStop{Fail{error}} 33 case Done{+text}: 34 read.more(String.is_empty(text), text, got) 35 36 # the answer when a file has not ended after every read file.read makes 37 def read.spent() -> Result<&1, &1, U32 & String, String>: 38 Fail{(27, "ezsys: file.read: the file did not end")} 39 40 # where file.save writes before it renames 41 def save.tmp(path: String) -> String: 42 path ++ ".tmp" 43 44 # what the temporary file's write answer means 45 def save.step(res: Result<&1, &1, U32 & String, Unit>) -> Save: 46 match res: 47 case Fail{error}: 48 SaveStop{error} 49 case Done{_u}: 50 SaveMove{} 51 52 # an environment variable's value, or the fallback when it is unset 53 def env.pick( 54 res: Result<&1, &1, U32 & String, String>, 55 fallback: String 56 ) -> String: 57 match res: 58 case Fail{_error}: 59 fallback 60 case Done{value}: 61 value