/
nv-lang
/
nova
Обзор
Документация
Войти
/
nv-lang
/
nova
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
main
std/src/io/error.nv
157 строк
7 KB
Evgeniy Golovin
docs(std/src): clean comments batch 17 — io, ffi/cstr, fs, os, net families
01 авг 2026, 12:24
01 авг 2026, 12:24
c82cd98
Код
Авторство
О чём код?
// SPDX-License-Identifier: MIT OR Apache-2.0 // std/io/error.nv — structural I/O error. // // One `IoError` for the whole io/fs/os(+process) family. Rust // `io::Error{ErrorKind}` precedent: an OPEN `ErrorKind` enum (wildcard-forced) // + a `raw_os` errno escape hatch + `op`/`path` context. Beats Go/Node // stringly-typed `err.code` and Java checked-exception noise; the Zig per-op // error-set alternative is considered/REJECTED — one open `ErrorKind` // composes instead of fragmenting handling per operation. // // Result-everywhere: io is a fallible domain → every fallible op returns // `Result[T, IoError]`, never `Fail`/throw. // // **Forward-notes (added when fs lands):** // - `path Option[Path]` — path-bearing fs errors. Deferred with byte-backed // `Path` itself: `Path` is a `value { ro bytes []u8 }` named record that // monomorphises cleanly as `Option[Path]`; console I/O (io-core) has no path, // so the field carries nothing here and is added at the constructor funnel. // - `source Option[*IoError]` — a boxed error chain (Rust `Box<dyn Error>`), // added when fs error-wrapping needs it; io-core errors are leaves (console // I/O never wraps a cause), so no chain is built yet. module std.io /// Category of an I/O failure. OPEN enum (Rust `ErrorKind` precedent) — a /// `match` over it MUST carry a wildcard arm (`Other(raw)` + future variants). /// Rare/obscure errnos (ENAMETOOLONG, …) map to `Other(raw_os)` — documented in /// the error-index. The connection-* variants exist for the net unification /// (`NetError` projects onto this enum). /// /// Zig-style per-op error sets were considered and REJECTED: exact /// per-operation error unions need error-union infrastructure and fragment /// handling; Nova takes the Rust model — one open kind + `raw_os` + `source`. #stable(since = "0.1") export type ErrorKind enum | NotFound | PermissionDenied | AlreadyExists | NotADirectory | IsADirectory | DirectoryNotEmpty | WouldBlock | Interrupted | UnexpectedEof | WriteZero | InvalidInput | InvalidData | TimedOut | StorageFull | ReadOnlyFilesystem | CrossesDevices | BrokenPipe | ConnectionRefused | ConnectionReset | ConnectionAborted | NotConnected | AddrInUse | AddrNotAvailable | Unsupported | Other(int) /// Structural I/O error. Carries: /// - `kind` — the categorised `ErrorKind` (match with a wildcard arm). /// - `raw_os` — the raw OS error code (errno / GetLastError), or `0` when the /// error is synthesised by Nova (EOF, WriteZero, …). **Authoritative**: the /// `kind` projection is best-effort, `raw_os` is exact. /// - `op` — the failed operation name for diagnostics (`"read"`, `"write"`). /// /// A **`value` record**: a small, copyable structural error that /// flows by value through `Result[T, IoError]`, including the generic /// mono-dispatched loop helpers and protocol vtables. (The earlier heap-record /// form was a codegen workaround for the value-record-in-`Result`-error mono gap; /// that gap is now closed — the protocol vtable forward-declares the referenced /// `NovaRes_<ok>_NovaValue_IoError` mono, so the canonical `value` form compiles.) #stable(since = "0.1") export type IoError value { ro kind ErrorKind ro raw_os int ro op str } // ─── Constructors (funnel — path/source wiring lands here, not at call sites) ─── /// Leaf error with a categorised kind and an operation name. `raw_os = 0` /// (Nova-synthesised, no OS code). #stable(since = "0.1") export fn IoError.new(kind ErrorKind, op str) -> IoError => { kind, raw_os: 0, op } /// Error carrying a raw OS code. `kind` is the categorised projection of /// `raw_os` (see `kind_from_errno`); `raw_os` is preserved for exact reporting. #stable(since = "0.1") export fn IoError.from_os(raw_os int, op str) -> IoError => { kind: kind_from_errno(raw_os), raw_os, op } // ─── Predicates / accessors ─── /// True when this error is `Interrupted` (EINTR) — the retry signal for the std /// loop helpers (`read_exact`/`write_all`/`read_to_end`). #stable(since = "0.1") export fn IoError @is_interrupted() -> bool => match @kind { Interrupted => true, _ => false } // ─── errno → ErrorKind projection (best-effort; raw_os authoritative) ─── /// Best-effort projection of a raw OS error code onto an `ErrorKind`. Maps the /// common POSIX errno values (which the Windows CRT also uses for the shared /// subset); anything unmapped falls to `Other(raw_os)` — ENAMETOOLONG & co. → /// `Other`. `raw_os` on the `IoError` stays /// authoritative, so a platform-specific miss only coarsens `kind`, never loses /// information. Mirrors Rust `sys::decode_error_kind`. #stable(since = "0.1") export fn kind_from_errno(code int) -> ErrorKind { match code { 1 => PermissionDenied // EPERM 2 => NotFound // ENOENT 4 => Interrupted // EINTR 11 => WouldBlock // EAGAIN / EWOULDBLOCK (Linux) 13 => PermissionDenied // EACCES 17 => AlreadyExists // EEXIST 18 => CrossesDevices // EXDEV 20 => NotADirectory // ENOTDIR 21 => IsADirectory // EISDIR 22 => InvalidInput // EINVAL 28 => StorageFull // ENOSPC 30 => ReadOnlyFilesystem // EROFS 32 => BrokenPipe // EPIPE 39 => DirectoryNotEmpty // ENOTEMPTY (Linux) _ => Other(code) } } // ─── Rendering ─── /// Human-readable, lowercase description (no trailing newline). Includes the /// operation and raw OS code when present. #stable(since = "0.1") export fn IoError @to_str() -> str { ro base = kind_to_str(@kind) ro withop = if @op.is_empty() { base } else { "${base} (${@op})" } if @raw_os != 0 { "${withop} [os ${@raw_os}]" } else { withop } } /// Lowercase description of a bare `ErrorKind`. #stable(since = "0.1") export fn kind_to_str(k ErrorKind) -> str { match k { NotFound => "entity not found" PermissionDenied => "permission denied" AlreadyExists => "entity already exists" NotADirectory => "not a directory" IsADirectory => "is a directory" DirectoryNotEmpty => "directory not empty" WouldBlock => "operation would block" Interrupted => "operation interrupted" UnexpectedEof => "unexpected end of file" WriteZero => "write returned zero" InvalidInput => "invalid input parameter" InvalidData => "invalid data" TimedOut => "operation timed out" StorageFull => "no storage space" ReadOnlyFilesystem => "read-only filesystem" CrossesDevices => "cross-device link" BrokenPipe => "broken pipe" ConnectionRefused => "connection refused" ConnectionReset => "connection reset" ConnectionAborted => "connection aborted" NotConnected => "not connected" AddrInUse => "address in use" AddrNotAvailable => "address not available" Unsupported => "unsupported operation" Other(code) => "other os error ${code}" } }