Module fs/temp
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
Temporary directory that can be cleaned up with remove.
Fields
| Name | Type | Description |
|---|---|---|
_path | Path | |
_removed | bool |
Trait Implementations
impl(TempDir, ...)
new_in : (TempDir) fn(parent : Path, io : Io) -> Impl(Future(TempDir, IoExn))Create a uniquely named directory inside parent and return a handle
that removes it on drop — Rust's tempfile::TempDir::new_in.
The name is parent/yo_tmp_XXXXXX resolved by mkdtemp(3), which
creates the directory itself with mode 0700 — a temporary directory
is never briefly world-readable — and retries until the name is unused.
Windows takes the non-atomic path described in the module header. Async:
awaited on the event loop, and it throws IoExn carrying the errno if
parent does not exist, is not writable, or a name cannot be won.
Parameters
| Name | Type | Notes |
|---|---|---|
parent | Path | |
io | Io |
new : (TempDir) fn(io : Io) -> Impl(Future(TempDir, IoExn))path : (TempDir) fn(self : TempDir) -> Pathremove : (TempDir) fn(self : TempDir, io : Io) -> Impl(Future(unit, IoExn))Remove the directory now and observe the outcome, instead of leaving it
to Dispose.
NON-RECURSIVE (rmdir), so it throws IoExn (ENOTEMPTY) if anything
is still inside — use walker.remove_dir_all for a populated tree.
Idempotent: a second call is a no-op, and so is the Dispose that
follows, because both consult the same _removed flag. Async, awaited
on the event loop.
Parameters
| Name | Type | Notes |
|---|---|---|
self | TempDir | |
io | Io |
Returns: Impl(Future(unit, IoExn))
impl(TempDir, Dispose(...))
dispose : (TempDir) fn(self : TempDir) -> unitRelease the resources self owns — a file descriptor, a socket, a lock,
a buffer the allocator handed out. Called automatically when the value's
owner drops it (a value type) or the last reference to it goes away (a
reference type), 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, and a type that also exposes an
explicit close/release is responsible for making the second call a
no-op.
Parameters
| Name | Type | Notes |
|---|---|---|
self | TempDir |
Returns: unit
Temporary file backed by a File handle.
Fields
| Name | Type | Description |
|---|---|---|
_file | File | |
_path | Path | |
_removed | bool |
Trait Implementations
impl(TempFile, ...)
new_in : (TempFile) fn(parent : Path, io : Io) -> Impl(Future(TempFile, 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
| Name | Type | Notes |
|---|---|---|
parent | Path | |
io | Io |
new : (TempFile) fn(io : Io) -> Impl(Future(TempFile, IoExn))file : (TempFile) fn(self : TempFile) -> FileThe 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
| Name | Type | Notes |
|---|---|---|
self | TempFile |
Returns: File
path : (TempFile) fn(self : TempFile) -> Pathremove : (TempFile) fn(self : TempFile, io : Io) -> Impl(Future(unit, 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
| Name | Type | Notes |
|---|---|---|
self | TempFile | |
io | Io |
Returns: Impl(Future(unit, IoExn))
impl(TempFile, Dispose(...))
dispose : (TempFile) fn(self : TempFile) -> unitRelease the resources self owns — a file descriptor, a socket, a lock,
a buffer the allocator handed out. Called automatically when the value's
owner drops it (a value type) or the last reference to it goes away (a
reference type), 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, and a type that also exposes an
explicit close/release is responsible for making the second call a
no-op.
Parameters
| Name | Type | Notes |
|---|---|---|
self | TempFile |
Returns: unit