Module fs/temp

fs/temp
Stability: unstable — the naming half of `tempfile`'s API is missing and adding it changes what these types are. Both spellings here are NAMED temporaries (Rust's `NamedTempFile`, `TempDir`): the name is fixed at `<parent>/yo_tmp_XXXXXX` with no way to set the prefix, the suffix, or a number of random characters — `tempfile`'s `Builder` — and there is no unnamed `tempfile()`, the form that unlinks immediately so the file cannot leak if the process dies. `keep()`/`into_path()` (disarm the cleanup and hand the caller the path) are also absent, so a temporary that should be promoted to a real file has to be copied. Freezing follows a `Builder` and a decision on the unnamed form, not a release count. — stable modules only change additively; this one may still change.

RAII-managed temporary files and directories.

Both types clean up on drop (Dispose), BEST-EFFORT: errors are ignored, and directory removal is non-recursive (same as remove — it succeeds only when the directory is empty). Call remove(io) explicitly when you need to observe removal errors.

Example

{ TempDir } :: import "std/fs/temp";

main :: (fn(io : Io, exn : Exception) -> unit)({
  dir := io.await(TempDir.new(io), { io, exn });
  println(dir.path());
  io.await(dir.remove(io), { io, exn });  // or let Dispose clean up on drop
});

Platform caveat — Windows naming is not atomic

mkdtemp/mkstemp are POSIX primitives that PICK the name and CREATE the entry in one uninterruptible step, retrying until they win. The Windows runtime cannot: it calls _wmktemp_s to invent a name and then _wmkdir/_wopen(_O_CREAT | _O_EXCL) to create it (src/codegen/async/runtime_io_windows.yo). That leaves a window between the two, and _wmktemp_s offers only 26 candidate names per template per process with no retry here, so both constructors can throw EEXIST on Windows where POSIX would simply pick another name (issues/stddoc-io-windows-temp-naming-is-not-atomic.md). Treat a TempDir/TempFile construction as fallible on that platform even when the parent directory is perfectly writable.

Stability

unstable — the naming half of tempfile's API is missing and adding it changes what these types are. Both spellings here are NAMED temporaries (Rust's NamedTempFile, TempDir): the name is fixed at <parent>/yo_tmp_XXXXXX with no way to set the prefix, the suffix, or a number of random characters — tempfile's Builder — and there is no unnamed tempfile(), the form that unlinks immediately so the file cannot leak if the process dies. keep()/into_path() (disarm the cleanup and hand the caller the path) are also absent, so a temporary that should be promoted to a real file has to be copied. Freezing follows a Builder and a decision on the unnamed form, not a release count.

Types

TempDir object
TempDir

Temporary directory that can be cleaned up with remove.

Fields

NameTypeDescription
_pathPath
_removedbool

Trait Implementations

impl(TempDir, ...)
new_in : (TempDir) fn(parent : Path, io : Io) -> Impl : (Future[Future](TempDir) IoExn : IoExn)

Create a uniquely named file inside parent, open it, and return a handle that closes and unlinks it on drop — Rust's tempfile::NamedTempFile::new_in.

mkstemp(3) does the naming, so on POSIX the create-and-open is atomic (O_EXCL) and the file is mode 0600 from the instant it exists — a temporary is never briefly world-readable. Windows takes the non-atomic path described in the module header. Async: awaited on the event loop, and throws IoExn with the errno on failure.

Parameters

NameTypeNotes
parentPath
ioIo

Returns: Impl : (Future[Future](TempDir) IoExn : IoExn)

new : (TempDir) fn(io : Io) -> Impl : (Future[Future](TempDir) IoExn : IoExn)

new_in against the system temporary directory (env.temp_dir()) — Rust's tempfile::NamedTempFile::new.

Parameters

NameTypeNotes
ioIo

Returns: Impl : (Future[Future](TempDir) IoExn : IoExn)

path : (TempDir) fn(self : TempDir) -> Path

The file's real path, as mkstemp resolved it. Handing this to another process is the reason a NAMED temporary exists; note the file is unlinked when this handle drops, so the path outlives nothing.

Parameters

NameTypeNotes
selfTempDir

Returns: Path

remove : (TempDir) fn(self : TempDir, io : Io) -> Impl : (Future[Future](unit) IoExn : IoExn)

Close the descriptor and unlink the file now, observing the outcome, instead of leaving it to Dispose. The close comes FIRST so that Windows can delete the file at all (POSIX allows unlinking an open file; Windows does not). Idempotent, and the following Dispose becomes a no-op. Async, awaited on the event loop; throws IoExn if either step fails.

Parameters

NameTypeNotes
selfTempDir
ioIo

Returns: Impl : (Future[Future](unit) IoExn : IoExn)

impl(TempDir, Dispose(...))
dispose : (TempDir) fn(self : TempDir) -> unit

Release the resources self owns — a file descriptor, a socket, a lock, a buffer the allocator handed out. Called automatically when the last reference to the value goes away, so an implementor never calls it directly and must tolerate being the only one who ever does.

It must be safe to run exactly once: the runtime calls it at refcount zero, and a type that also exposes an explicit close/release is responsible for making the second call a no-op.

Parameters

NameTypeNotes
selfTempDir

Returns: unit

TempFile object
TempFile

Temporary file backed by a File handle.

Fields

NameTypeDescription
_fileFile
_pathPath
_removedbool

Trait Implementations

impl(TempFile, ...)
new_in : (TempFile) fn(parent : Path, io : Io) -> Impl : (Future[Future](TempFile) IoExn : IoExn)

Create a uniquely named file inside parent, open it, and return a handle that closes and unlinks it on drop — Rust's tempfile::NamedTempFile::new_in.

mkstemp(3) does the naming, so on POSIX the create-and-open is atomic (O_EXCL) and the file is mode 0600 from the instant it exists — a temporary is never briefly world-readable. Windows takes the non-atomic path described in the module header. Async: awaited on the event loop, and throws IoExn with the errno on failure.

Parameters

NameTypeNotes
parentPath
ioIo

Returns: Impl : (Future[Future](TempFile) IoExn : IoExn)

new : (TempFile) fn(io : Io) -> Impl : (Future[Future](TempFile) IoExn : IoExn)

new_in against the system temporary directory (env.temp_dir()) — Rust's tempfile::NamedTempFile::new.

Parameters

NameTypeNotes
ioIo

Returns: Impl : (Future[Future](TempFile) IoExn : IoExn)

file : (TempFile) fn(self : TempFile) -> File

The open File behind this temporary, for reading and writing it. The TempFile keeps its own reference, so this does NOT hand over ownership: closing the returned handle leaves the TempFile's cleanup to unlink a file it no longer has open, which is harmless. The handle starts at position 0 — write, then seek back before reading.

Parameters

NameTypeNotes
selfTempFile

Returns: File

path : (TempFile) fn(self : TempFile) -> Path

The file's real path, as mkstemp resolved it. Handing this to another process is the reason a NAMED temporary exists; note the file is unlinked when this handle drops, so the path outlives nothing.

Parameters

NameTypeNotes
selfTempFile

Returns: Path

remove : (TempFile) fn(self : TempFile, io : Io) -> Impl : (Future[Future](unit) IoExn : IoExn)

Close the descriptor and unlink the file now, observing the outcome, instead of leaving it to Dispose. The close comes FIRST so that Windows can delete the file at all (POSIX allows unlinking an open file; Windows does not). Idempotent, and the following Dispose becomes a no-op. Async, awaited on the event loop; throws IoExn if either step fails.

Parameters

NameTypeNotes
selfTempFile
ioIo

Returns: Impl : (Future[Future](unit) IoExn : IoExn)

impl(TempFile, Dispose(...))
dispose : (TempFile) fn(self : TempFile) -> unit

Release the resources self owns — a file descriptor, a socket, a lock, a buffer the allocator handed out. Called automatically when the last reference to the value goes away, so an implementor never calls it directly and must tolerate being the only one who ever does.

It must be safe to run exactly once: the runtime calls it at refcount zero, and a type that also exposes an explicit close/release is responsible for making the second call a no-op.

Parameters

NameTypeNotes
selfTempFile

Returns: unit