/
nv-lang
/
nova-http
Обзор
Документация
Войти
/
nv-lang
/
nova-http
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
main
src/status.nv
207 строк
8 KB
Evgeniy Golovin
style(225.1): вертикальный ритм — sweep классов a/b/e (src)
26 июл 2026, 02:21
26 июл 2026, 02:21
d0e6b36
Код
Авторство
О чём код?
// SPDX-License-Identifier: MIT OR Apache-2.0 // nova-http: status.nv — HTTP status code (D358). Extracted from monorepo // std/http (Plan 203 Ф.1). // // value-newtype (D215) над u16, диапазон 100..599. Классы 1xx..5xx + канонические // reason-phrases (для логов; на проводе reason игнорируется при разборе, RFC 7230 // §3.1.2). 4xx/5xx — ВАЛИДНЫЙ Response, НЕ ошибка (Q4): конверсия в ошибку — // opt-in `response.error_for_status()` (Ф.2). module http /// HTTP status code (100..599). Field is `int` (Nova's address-sized native /// integer), NOT `u16` — plan 222.5 §4а Q1 (`[M-statuscode-u16-cast-bounce]`): /// statuses aren't stored in bulk, so `u16`'s 6-byte saving is a wash, while /// the cost was real (7+ `.as_u16() as int` cast-bridges across the package, /// since `ServerResponse.status`/wire parsing all work in `int`). No `u16` /// anywhere in the public surface anymore either (owner correction /// 2026-07-24): the numeric accessor is the plain property `@code() -> int` /// (nv-coding-style same-name-by-arity convention), not an `as_*`-prefixed /// narrowing method — `u16` only ever appears at the true wire boundary /// (ASCII-digit parsing), never as internal storage or a public return type. #stable(since = "0.1") export type StatusCode value { priv code int } /// Named associated constants (plan 222.5 §4а-РЕШЕНИЕ, out-of-body form, /// D200 amendment / window №66): the one door for frequent literal /// StatusCode values. Full names per the `http::StatusCode` convention /// (Rust `http` crate), UPPER_SNAKE (cf. `Duration.SECOND`). Named factory /// functions are RETRACTED (D9 — a const and a zero-arg wrapper fn over the /// same value would be two doors) — see call-site migration across the /// package. #stable(since = "0.1") const StatusCode.OK StatusCode = { code: 200 } #stable(since = "0.1") const StatusCode.CREATED StatusCode = { code: 201 } #stable(since = "0.1") const StatusCode.NO_CONTENT StatusCode = { code: 204 } #stable(since = "0.1") const StatusCode.MOVED_PERMANENTLY StatusCode = { code: 301 } #stable(since = "0.1") const StatusCode.FOUND StatusCode = { code: 302 } #stable(since = "0.1") const StatusCode.NOT_MODIFIED StatusCode = { code: 304 } #stable(since = "0.1") const StatusCode.BAD_REQUEST StatusCode = { code: 400 } #stable(since = "0.1") const StatusCode.UNAUTHORIZED StatusCode = { code: 401 } #stable(since = "0.1") const StatusCode.FORBIDDEN StatusCode = { code: 403 } #stable(since = "0.1") const StatusCode.NOT_FOUND StatusCode = { code: 404 } #stable(since = "0.1") const StatusCode.METHOD_NOT_ALLOWED StatusCode = { code: 405 } #stable(since = "0.1") const StatusCode.REQUEST_TIMEOUT StatusCode = { code: 408 } #stable(since = "0.1") const StatusCode.PAYLOAD_TOO_LARGE StatusCode = { code: 413 } #stable(since = "0.1") const StatusCode.UPGRADE_REQUIRED StatusCode = { code: 426 } #stable(since = "0.1") const StatusCode.TOO_MANY_REQUESTS StatusCode = { code: 429 } #stable(since = "0.1") const StatusCode.INTERNAL_SERVER_ERROR StatusCode = { code: 500 } #stable(since = "0.1") const StatusCode.BAD_GATEWAY StatusCode = { code: 502 } #stable(since = "0.1") const StatusCode.SERVICE_UNAVAILABLE StatusCode = { code: 503 } /// Класс статуса (первая цифра). #stable(since = "0.1") export type StatusClass enum | Informational | Success | Redirection | ClientError | ServerError /// Сконструировать из `int`; вне 100..599 → `Protocol`. (Was `u16` — §4а Q1; /// callers holding a wire-parsed number no longer need an `as u16` bridge.) #stable(since = "0.1") export fn StatusCode.new(code int) -> Result[StatusCode, HttpError] { if code < 100 || code > 599 { return Err(HttpError.protocol_error("status code out of range 100..599")) } Ok({ code }) } /// Unchecked construction from a raw `int` — NO 100..599 validation /// (plan 222.5 §4б-финал: `unsafe`, escape-hatch, std-precedent /// `to_str`/`to_str_unchecked`; skipping the check can mint an invalid /// StatusCode that breaks the `@class()` invariant — the invariant is on the /// caller). Internal bridge for the DEPRECATED bare-`int` `ServerResponse` /// constructors (`server.nv`, soft migration — plan 222.5 §4а item 3): those /// overloads never validated their status before this unification either, so /// this preserves that exact (permissive) legacy behaviour instead of /// introducing a new panic/error path for the existing bare-int call-sites /// across the package. Prefer `StatusCode.new`/the named constants for /// validated construction — this is NOT part of the normal public surface. #stable(since = "0.1") export unsafe fn StatusCode.new_unchecked(code int) -> StatusCode => { code } /// Числовое значение (property accessor over `priv code` — nv-coding-style /// same-name-by-arity convention, mirrors `Json[T] @data()`/`Response /// @status()` elsewhere in the package). Owner correction 2026-07-24: the /// former `@as_u16() -> u16` was a double violation — an `as_*`-prefixed /// name (against the property convention) that ALSO went stale the moment /// the field widened to `int` (§4а Q1) — a real narrowing cast had nothing /// left to narrow FROM once callers just wanted the field's own `int`. /// `[M-d410-as-to-migration]` — CLOSED here, this is the correct form. #stable(since = "0.1") export fn StatusCode @code() -> int => @code /// Класс статуса. #stable(since = "0.1") export fn StatusCode @class() -> StatusClass { if @code < 200 { Informational } else if @code < 300 { Success } else if @code < 400 { Redirection } else if @code < 500 { ClientError } else { ServerError } } /// 1xx. #stable(since = "0.1") export fn StatusCode @is_informational() -> bool => @code >= 100 && @code < 200 /// 2xx. #stable(since = "0.1") export fn StatusCode @is_success() -> bool => @code >= 200 && @code < 300 /// 3xx. #stable(since = "0.1") export fn StatusCode @is_redirect() -> bool => @code >= 300 && @code < 400 /// 4xx. #stable(since = "0.1") export fn StatusCode @is_client_error() -> bool => @code >= 400 && @code < 500 /// 5xx. #stable(since = "0.1") export fn StatusCode @is_server_error() -> bool => @code >= 500 && @code < 600 /// Канонический reason-phrase (RFC 9110); неизвестный код → "". #stable(since = "0.1") export fn StatusCode @reason() -> str { match @code { 100 => "Continue" 101 => "Switching Protocols" 102 => "Processing" 103 => "Early Hints" 200 => "OK" 201 => "Created" 202 => "Accepted" 203 => "Non-Authoritative Information" 204 => "No Content" 205 => "Reset Content" 206 => "Partial Content" 207 => "Multi-Status" 208 => "Already Reported" 226 => "IM Used" 300 => "Multiple Choices" 301 => "Moved Permanently" 302 => "Found" 303 => "See Other" 304 => "Not Modified" 305 => "Use Proxy" 307 => "Temporary Redirect" 308 => "Permanent Redirect" 400 => "Bad Request" 401 => "Unauthorized" 402 => "Payment Required" 403 => "Forbidden" 404 => "Not Found" 405 => "Method Not Allowed" 406 => "Not Acceptable" 407 => "Proxy Authentication Required" 408 => "Request Timeout" 409 => "Conflict" 410 => "Gone" 411 => "Length Required" 412 => "Precondition Failed" 413 => "Content Too Large" 414 => "URI Too Long" 415 => "Unsupported Media Type" 416 => "Range Not Satisfiable" 417 => "Expectation Failed" 418 => "I'm a teapot" 421 => "Misdirected Request" 422 => "Unprocessable Content" 423 => "Locked" 424 => "Failed Dependency" 425 => "Too Early" 426 => "Upgrade Required" 428 => "Precondition Required" 429 => "Too Many Requests" 431 => "Request Header Fields Too Large" 451 => "Unavailable For Legal Reasons" 500 => "Internal Server Error" 501 => "Not Implemented" 502 => "Bad Gateway" 503 => "Service Unavailable" 504 => "Gateway Timeout" 505 => "HTTP Version Not Supported" 506 => "Variant Also Negotiates" 507 => "Insufficient Storage" 508 => "Loop Detected" 510 => "Not Extended" 511 => "Network Authentication Required" _ => "" } }