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

OpenFailure

OpenFailure : FaultSource

Fails acquisition before creating or truncating anything.

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.

CloseFailure

CloseFailure : FaultSource

Fails the first close after invalidating the handle.

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.

Fields

value

value : aSource

The action’s result.

image

image : ImageSource

The final image, independent of subsequent runners.

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.