APIFile
File
Files and directories.
withFile, withOutput, and withAppend open a file as a Handle
for the length of a callback and close it exactly once when the callback
exits, however it exits. A failed open raises before anything is acquired.
A failed close after a successful callback is the scope’s failure; after a
failed one it is recorded beside it. A handle that escapes its scope
reports a closed-resource error when used. Closing a handle interrupts a
blocked read on it.
Whole-file and directory operations perform FileSystem and answer a
Result. runSystem is its default and resolves relative paths from the
program’s working directory; runMemory interprets them without OS access.
Streaming operations use the same effect. Handles belong to one runner and
become invalid when closed or when that runner exits.
Fault
type Fault = OpenFailure | ReadFailure Int | WriteFailure Int | CloseFailureSource
A deterministic fault for runMemoryWith.
Constructors
ReadFailure
ReadFailure : Int -> FaultSource
Allows this many bytes per open handle, then fails a read while input remains. EOF and nonpositive-count probes do not consume the budget.
WriteFailure
WriteFailure : Int -> FaultSource
Writes at most this many bytes per open handle; a short write fails after publishing its prefix.
Instances:
Eq Fault
Show Fault
Faults
type FaultsSource
Faults by normalized path. They configure a run rather than the image, so a returned snapshot carries none of them.
Handle
type HandleSource
A file handle. It cannot be forged, inspected, or compared. The standard runners reject a handle created by another provider, and use after close or after its provider exits.
Image
type ImageSource
An opaque immutable filesystem fixture. Paths use /, with / as both
root and working directory. Repeated separators and . are removed;
.. moves to the parent and stays at root there. Empty paths and NUL are
invalid. No symlinks, permissions, or host path lookup are modeled.
Provider
type ProviderSource
The identity of one handler’s files. A custom handler that creates handles
gets a fresh provider from withProvider; comparing a handle’s provider
tells its own handles apart from those of nested or earlier handlers.
Snapshot
type Snapshot a = { value : a , image : Image }Source
An action’s result and the final immutable filesystem image.
FileSystem
effect FileSystemSource
File acquisition, streaming access, and whole-file/directory queries. Every operation is public so custom handlers can interpret the complete boundary.
Operations
openRead
openRead : String ->{FileSystem} Result Error HandleSource
Opens a file for reading. Raw acquisitions must be closed by the caller; the provider also invalidates remaining handles at its exit.
openWrite
openWrite : String ->{FileSystem} Result Error HandleSource
Creates or truncates a file and opens it for writing.
openAppend
openAppend : String ->{FileSystem} Result Error HandleSource
Opens a file for append, creating it when needed.
closeHandle
closeHandle : Handle ->{FileSystem} Result Error ()Source
Closes a handle. Repeated close under its owning provider succeeds.
readHandleLine
readHandleLine : Handle ->{FileSystem} Result Error (Maybe Line)Source
The next line, or Nothing at EOF. Invalid UTF-8 is replaced with U+FFFD.
readHandleBytes
readHandleBytes : Handle -> Int ->{FileSystem} Result Error (Maybe Bytes)Source
Up to count bytes, bounded by 64 KiB, or Nothing at EOF. A nonpositive
count answers empty bytes while input remains.
writeHandleBytes
writeHandleBytes : Handle -> Bytes ->{FileSystem} Result Error ()Source
Writes all bytes; failure may leave a written prefix.
readFileResult
readFileResult : String ->{FileSystem} Result Error StringSource
Reads the file as text, replacing each consecutive run of malformed UTF-8 with U+FFFD.
writeFileResult
writeFileResult : String -> String ->{FileSystem} Result Error ()Source
Creates or replaces a file with UTF-8 text; its parent must exist.
isDirectoryPath
isDirectoryPath : String ->{FileSystem} Result Error BoolSource
Whether the path names a directory.
fileSize
fileSize : String ->{FileSystem} Result Error IntSource
The file’s size in bytes. Directory sizes are provider-specific.
listDirectory
listDirectory : String ->{FileSystem} Result Error (List String)Source
The immediate entry names of the directory, sorted.
empty
empty : ImageSource
An image containing only the root directory.
handleKey
handleKey : Provider -> Handle -> Result Error IntSource
The backend key of a handle this provider created. Any other handle,
including a system one, answers foreign handle; after the provider exits,
closed provider. Both are IO.Other errors at the handle’s path.
isDirectory
isDirectory : String ->{FileSystem} Result Error BoolSource
Whether path names a directory rather than a file.
newHandle
newHandle : Provider -> String -> Int -> HandleSource
A handle owned by the provider, for path and the handler’s own backend
key. The handler chooses keys and must not reuse one within a provider:
whether a key is still open is the handler’s own state, so a reused key
would make a closed handle valid again.
noFaults
noFaults : FaultsSource
No injected faults.
read
read : String ->{FileSystem} Result Error StringSource
The whole contents of the file at path as text, with U+FFFD in place of
each consecutive run of malformed UTF-8.
readBytes
readBytes : Handle -> Int ->{Fail Error, FileSystem} Maybe BytesSource
Up to count bytes, at most 64 KiB, or Nothing at EOF. A nonpositive
count returns empty bytes while input remains. Reads may be short.
readLine
readLine : Handle ->{Fail Error, FileSystem} Maybe LineSource
The next line and its exact terminator, or Nothing at EOF. Byte and line
reads share one offset. A write-only, closed, or foreign handle fails.
runMemory
runMemory : Image -> (() ->{FileSystem, e} a) ->{e} Snapshot aSource
runMemoryWith noFaults.
import File
import IO
import Result exposing (Result(..))
changed = File.runMemory File.empty {
written = File.writeAll "greeting.txt" "Hello!"
File.read "greeting.txt"
}
changed.value == Ok "Hello!"
File.textAt "greeting.txt" changed.image == Ok "Hello!"
case File.textAt "greeting.txt" File.empty of
Err error -> error.kind == IO.NotFound
Ok _ -> False
runMemoryWith
runMemoryWith : Faults -> Image -> (() ->{FileSystem, e} a) ->{e} Snapshot aSource
Interprets FileSystem without OS access, returning an immutable snapshot. Reads/writes share the same image as whole-file calls; each open has its own offset. Appends choose the current end on every write. Raw handles are invalidated at provider exit; scoped handles close on every language exit. Faults apply to both streaming and whole-file operations.
Tasks that inherit the runner share its image. Each operation, including a whole-file read or write, applies atomically: concurrent reads through one handle never return the same bytes, and appends never overwrite one another. Operations from different tasks interleave in scheduling order. It models no symlinks or permissions. Directory sizes are zero. An abort escaping the runner returns no snapshot; put Fail.attempt inside it to inspect partial progress.
runSystem
runSystem : (() ->{FileSystem, e} a) ->{IO, e} aSource
Interprets FileSystem through the OS under a fresh provider. Scoped files close before their callbacks leave; remaining raw handles close and become invalid at runner exit. Raw acquisition callers must explicitly close their handles; teardown reports its first native close failure.
sink
sink : Handle -> Sink {Fail Error, FileSystem}Source
A byte sink borrowing the file. It takes no ownership and checks the handle’s provider and validity on every write.
size
size : String ->{FileSystem} Result Error IntSource
The size in bytes of the file at path.
source
source : Handle -> Source {Fail Error, FileSystem}Source
A byte source borrowing the file. It takes no ownership and checks the handle’s provider and validity on every pull.
textAt
textAt : String -> Image -> Result Error StringSource
The file’s text, replacing each consecutive run of malformed UTF-8 with U+FFFD, without running a service. Missing files and directory paths answer structured errors.
withAppend
withAppend : String -> (Handle ->{Fail Error, FileSystem, e} a) ->{Fail Error, FileSystem, e} aSource
Opens path for append, creating it if necessary, and closes on every exit.
withByteFile
withByteFile : String -> Bytes -> Image -> Result Error ImageSource
Adds or replaces a file and creates missing parents. A directory at the
path answers IsDirectory; a file parent answers NotDirectory.
withDirectory
withDirectory : String -> Image -> Result Error ImageSource
Adds a directory and missing parents. An existing directory is kept;
a file at the path or a parent answers NotDirectory.
withFault
withFault : String -> Fault -> Faults -> Result Error FaultsSource
Adds a fault for this normalized path, including paths not yet present.
Later faults of the same kind take precedence. Negative byte limits and
invalid paths answer IO.Other.
import File exposing (Fault(..))
import Result exposing (Result(..))
case File.withFault "data" (WriteFailure 2) File.noFaults of
Ok faults ->
run = File.runMemoryWith faults File.empty { File.writeAll "data" "hello" }
File.textAt "data" run.image == Ok "he"
Err _ -> False
withFile
withFile : String -> (Handle ->{Fail Error, FileSystem, e} a) ->{Fail Error, FileSystem, e} aSource
Opens path for reading, runs the callback, and closes exactly once on
normal return or a language abort. Failed acquisition releases nothing.
withOutput
withOutput : String -> (Handle ->{Fail Error, FileSystem, e} a) ->{Fail Error, FileSystem, e} aSource
Creates or truncates path, runs the callback, and closes on every exit.
A close failure after success becomes primary; after a body failure it is
recorded as a suppressed failure.
withProvider
withProvider : (Provider ->{e} a) ->{e} aSource
Gives a custom handler a fresh provider and retires it on every exit of
action. Handles created under it, including any the result carries, then
answer closed provider.
withTextFile
withTextFile : String -> String -> Image -> Result Error ImageSource
Like withByteFile, storing the UTF-8 bytes of the text.
import File
import Result exposing (Result(..))
case File.withTextFile "config/settings" "ready" File.empty of
Ok image -> File.textAt "config/./settings" image == Ok "ready"
Err _ -> False
write
write : Handle -> String ->{Fail Error, FileSystem} ()Source
Writes all UTF-8 bytes of the text without adding a newline.
writeAll
writeAll : String -> String ->{FileSystem} Result Error ()Source
Writes text as the whole contents of the file at path, creating or
replacing it.
writeBytes
writeBytes : Handle -> Bytes ->{Fail Error, FileSystem} ()Source
Writes all bytes. A read-only, closed, or foreign handle fails.
