/
nv-lang
/
nova
Обзор
Документация
Войти
/
nv-lang
/
nova
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
main
std/src/net/error.nv
145 строк
6 KB
Evgeniy Golovin
merge: comment-hygiene-2 — чистка комментариев std (batch 1-20) + линт-свип 330→13
01 авг 2026, 18:13
01 авг 2026, 18:13
bb8b33d
Код
Авторство
О чём код?
// SPDX-License-Identifier: MIT OR Apache-2.0 // std/net/error.nv — typed network error. // // The C transport returns UV error codes (int, <0). The typed NetError is built // on the Nova side from that code via `NetError.from_code`: the code is turned // into text by the layer's `net_strerror` (which canonicalises EACCES / // ECONNRESET), and that text is classified into a typed variant. No TLS, no // C-side error state — the honest error channel replacing the заход-1 null stub. // // `NetError` → shared `io.ErrorKind` projection. Kept as an // ADDITIVE best-effort mapping (`@to_error_kind`/`@to_io_error`), NOT a rename — // `NetError` and its `@to_str()` strings are UNCHANGED (smaller diff than // updating every net fixture that asserts on them; chosen per the "sохранить // строки ИЛИ обновить фикстуры" option). The projection backs `TcpStream.@read`/ // `@write`'s `io.Read`/`io.Write` conformance (tcp.nv) and // `HttpError.ErrSource.Net` (std/http/error.nv). module std.net import std.io.{ErrorKind, IoError} /// Network error returned by TCP/UDP/DNS operations. /// /// # See Also /// /// - `[TcpListener]`, `[TcpStream]`, `[UdpSocket]` #stable(since = "0.1") export type NetError enum | ConnectionRefused | AddressInUse | AddressNotAvailable | NotFound | Eof | Closed | Cancelled | TimedOut | BrokenPipe | ConnectionReset | PermissionDenied | IoError(str) | InvalidAddr(str) | InvalidPort /// Human-readable, lowercase description of this error (no trailing newline). /// /// ```nova /// assert(NetError.ConnectionRefused.to_str() == "connection refused") /// assert(NetError.Eof.to_str() == "end of file") /// ``` #stable(since = "0.1") export fn NetError @to_str() -> str { match @ { ConnectionRefused => "connection refused" AddressInUse => "address already in use" AddressNotAvailable => "address not available" NotFound => "not found" Eof => "end of file" Closed => "connection closed" Cancelled => "operation cancelled" TimedOut => "operation timed out" BrokenPipe => "broken pipe" ConnectionReset => "connection reset by peer" PermissionDenied => "permission denied" IoError(msg) => msg InvalidAddr(msg) => "invalid address: ${msg}" InvalidPort => "invalid port" } } // ─── UV-code → NetError (the honest error channel) ──────────────────────────── /// Build a typed `NetError` from a libuv error code (the transport's `<0` /// return / `out_err` cell). The message text comes from the layer's /// `net_strerror`; classification is by canonical substring. #stable(since = "0.1") export fn NetError.from_code(code int) -> NetError { ro msg = strerror_text(code) classify(msg) } // Layer error text for a UV code into a Nova str (no TLS; caller buffer). fn strerror_text(code int) -> str { mut buf []u8 = []u8.new() buf.resize(256, 0 as u8) ro n = unsafe { net_strerror(code, buf.ptr(), 256) } // [M-174.1-vec-method-chain-elem-erasure]: explicit []u8 local; non-unsafe // decode + `??` fallback (uv_strerror text is ASCII) — same P67 gap as // SocketAddr @ip (addr.nv). ro msg_bytes []u8 = buf[..n] msg_bytes.to_str() ?? "" } // Classify a canonical uv_strerror message into a typed NetError. The C layer // normalises EACCES → "permission denied" and ECONNRESET → "connection reset by // peer", so substring matching here is platform-stable. fn classify(msg str) -> NetError { if msg.contains("connection refused") { NetError.ConnectionRefused } else if msg.contains("address already in use") { NetError.AddressInUse } else if msg.contains("address not available") { NetError.AddressNotAvailable } else if msg.contains("permission denied") { NetError.PermissionDenied } else if msg.contains("connection reset") { NetError.ConnectionReset } else if msg.contains("broken pipe") { NetError.BrokenPipe } else if msg.contains("canceled") || msg.contains("cancelled") { NetError.Cancelled } else if msg.contains("timed out") { NetError.TimedOut } else if msg.contains("not found") || msg.contains("unknown node") || msg.contains("no address") { NetError.NotFound } else { NetError.IoError(msg) } } // ─── NetError → ErrorKind projection ────────────────────────────────────────── /// Best-effort projection onto the shared io/fs/os `ErrorKind`. Lossy where /// net has no exact counterpart (`Closed`→`NotConnected`, `Cancelled`→ /// `Interrupted`, `IoError(msg)`/`InvalidAddr(msg)`/`InvalidPort`→`InvalidInput`/ /// `Other` — text detail is NOT carried, only the coarse kind); `raw_os` on the /// resulting `IoError` is always `0` (the uv code was already consumed by /// `classify()` — not recoverable here). `@to_str()` keeps reporting via /// `NetError`'s own strings; this projection is for cross-domain conformance /// (`io.Read`/`io.Write` on `TcpStream`), not for display. #stable(since = "0.1") export fn NetError @to_error_kind() -> ErrorKind { match @ { ConnectionRefused => ErrorKind.ConnectionRefused AddressInUse => ErrorKind.AddrInUse AddressNotAvailable => ErrorKind.AddrNotAvailable NotFound => ErrorKind.NotFound Eof => ErrorKind.UnexpectedEof Closed => ErrorKind.NotConnected Cancelled => ErrorKind.Interrupted TimedOut => ErrorKind.TimedOut BrokenPipe => ErrorKind.BrokenPipe ConnectionReset => ErrorKind.ConnectionReset PermissionDenied => ErrorKind.PermissionDenied IoError(_) => ErrorKind.Other(0) InvalidAddr(_) => ErrorKind.InvalidInput InvalidPort => ErrorKind.InvalidInput } } /// Build a shared `io.IoError` from this `NetError` (projection + `op` for /// diagnostics). Used to give `TcpStream` structural `io.Read`/`io.Write` /// conformance without changing the `Net` effect's own `NetError` surface /// (`write_all`/`read_bytes`/`read_text`/the split halves keep returning /// `NetError` directly). #stable(since = "0.1") export fn NetError @to_io_error(op str) -> IoError => IoError.new(@to_error_kind(), op)