Glide v0.2.0
0.2.0 — 2026-05-25
Types
- Canonical fixed-width numeric types:
i8 i16 i32 i64 i128 i256/
u8 u16 u32 u64 u128 u256/usize isize/f32 f64. The legacy C-style
spellingsint / uint / long / ulong / floatare retired as type names —
using one is an error with a hint to the canonical replacement.i128/u128
are native (__int128);i256/u256are a first-class software 4×u64 struct
with operators dispatched to runtime helpers, built viau256::from(n).
Methods (.to_string(),.abs(), …) work across every width. - Associated int constants
i32::MAX/u64::MIN/ … for every integer
width (i128/i256 included). Unsigned.to_string()no longer prints via the
signed path (u64::MAXwas showing-1). - Anonymous tuples:
(A, B, ...)as a first-class structural type — tuple
literals(a, b), positional accesst.0/t.1(nestedt.0.1too),
multi-value return (fn divmod(...) -> (i32, i32)), tuple params / struct
fields,let (a, b) = expr;destructuring, and tuples wrapped in!T/?T.
Each unique element combination lowers to one C struct, so(i32, string)is
the same type everywhere. Complements thestruct Name(field: T)tuple-struct
sugar (which stays the way to name a value type).
Compiler
- Flexible
mainsignatures:fn main(),fn main() -> i32, and
fn main() -> !Tare all accepted; the C wrapper maps each to an exit code. - Compile-time
format!check: a{}placeholder / argument count
mismatch is reported at compile time instead of reading a missing printf arg. - First-use generic element inference:
let v = Vector::new()followed by
v.push(32)fixesvtoVector<int>, so a laterv.push("x")is flagged. pub import X::*re-exports the imported names, so a barrel module can
collect symbols from several files under one import.
HTTP
- HTTP/2 server with stream multiplexing (HPACK + frames + ALPN).
- HTTP/3: client over ngtcp2 + nghttp3 (interop-tested against Cloudflare),
a server (multi-connection, streaming response bodies, self-signed cert
helper), and 0-RTT end-to-end (session cache + TLS resumption, early-data
plumbing, anti-replay sliding window, disk persistence). H3 needs an
OpenSSL 3.5+ toolchain. - Router + decorators:
@route/@get/@post/ etc.,@middleware(...)
composed per route,@listen(port)/@listen_workers(port, n)rewrite
mainwith the router setup, androutes!(r). Method-aware router with
:param/*wildcardsegments. - OpenAPI 3.0.3 spec emitted from
@route'd handlers; route discovery
surfaced to the LSP (documentSymbol+glide/routeList,/glide-routes). - Extractors:
Form,Query<T>,Cookies, plus the existing typed
Json<T>/Path<T>/ headers / bearer extractors. - Server-Sent Events (production): keep-alive, comments, retry,
Last-Event-ID,SseChannel. - Static file middleware (production): ETag, directory-traversal guard,
index.html, expanded MIME map, zero-copy viasendfile/TransmitFile. - TLS: server-side ALPN advertise + select callback; configurable handshake
timeout + split-accept API.
Concurrency + runtime
- io_uring reactor (Linux), opt-in via
GLIDE_REACTOR=uring(+14% over
epoll). Joins the kqueue (macOS/BSD) and IOCP (Windows) backends below. @leaf+ stackless spawn: a@leafcoroutine runs inline on its worker
(~192 B/task).http_listen_workers/ the router use a state-machine fast
path by default (≈95% of Axum);@leafis auto-detected, no longer required
on handlers, and a blocking handler aborts cleanly.- Growable coroutine stacks (default 8 KiB, fault-driven grow) and a tuned
channel park path:park_unparkwent 23 µs → ~270 ns (per-worker run-next
slot + spin budget,GLIDE_CHAN_SPIN).
Macros
@proc_pass— whole-program compiler passes distributable as libraries;
pass_diaglets a pass emit custom lints (location + code + severity)
that get the same rendering and@allowsuppression as built-ins.@proc_macro_expr— proc-macros that return an expression (compile-time
values).- Import-aware macro resolution: bare
name!resolves across dependencies
with an ambiguity error;dep::name!disambiguates same-named macros by
origin module. stdlib::meta— a stable surface for compile-time macro libraries.
Package manager
- Import a dependency by its bare name;
glide new --libscaffolds a
library assrc/<name>.glide. - Git deps accept
file://andgit://remotes. - The manifest parses
author/license/description/repository
(informational) and they're scaffolded into a new project. glide checkwith no file resolves the project's entry point.
Cross-platform
- kqueue reactor backend for macOS, FreeBSD, OpenBSD, NetBSD,
and DragonFly. Replaces the sync I/O fallback those platforms
silently fell into via theif os_is_windows() { ... } else { spawn ... }branch inhttp_listen, which on macOS/BSD sent
every accepted conn through a syncreadthat pinned its
worker thread. - AArch64 (ARM64) context switch —
__glide_ctx_switchnow
carries anstp/ldpbackend that saves x19-x30 + d8-d15. Plus
ayield(vspause) hint in the spin loops and the
aarch64-linux-musltriple registered for cross builds. Lets
Glide run on Apple Silicon / Graviton / Pi 4-5 / any aarch64
host. Sysroot tarball still has to ship before
glide target add aarch64-linux-muslresolves. - Page size detected at runtime (
sysconf(_SC_PAGESIZE)/
GetSystemInfo). The previous hardcoded 4 KiB rounded the
guard page off the wrong slot on Apple Silicon (16 KiB native
pages) so a stack overflow could corrupt the next coro's stack
instead of tripping the guard. - SO_REUSEPORT dispatch per-OS.
http_listen_workersand
Router::listen_workersnow branch on
os_has_reuseport_balance()(Linux: each worker binds; macOS /
BSD / Windows: bind once + share the fd across N accept
threads). Previously the spawn path serialised on the silent
shared-bind semantics in macOS / BSD. - IOCP reactor for Windows.
tcp_read_async/
tcp_write_async/tcp_writev2_asyncissue OVERLAPPED ops
againstWSARecv/WSASend; a dedicated reactor thread
drainsGetQueuedCompletionStatusand unparks the issuing
coro.http_listennow spawns one coro per connection on
Windows —os_has_async_io()returns 1 there.accept_tcp_async
is still blocking (AcceptEx is a follow-up).
Codegen + bootstrap
- Top-level
c_raw! { ... }blocks emit AFTER the runtime
templates (scheduler + sockets + reactor) instead of before, so
bootstrap fallbacks in stdlib can#ifdef-guard against
symbols the runtime promised to provide
(__GLIDE_RUNTIME_HAS_REACTOR_ACTIVEetc). ccinvocation on Windows no longer wraps everything in an
outer"...". The wrap was meant to handle a quoted cc path
with spaces, but it brokecmd.exe /cparsing whenever the
inner argv already had quoted paths, leaving collect2 with the
raw.cfile as a "linker input" instead of a compiled.o.- New TLS flag
__glide_is_main_tlsset on the C main thread.
__glide_spawnfrom a foreign pthread (e.g. an http_listen
accept loop running on its ownspawn_thread) now pushes onto
the worker queue directly instead of buffering up to a batch of
32 that may never arrive. The first 31 conns of a server thread
used to sit unprocessed waiting for conn #32.
Ownership
- Non-lexical lifetimes: a borrow's lifetime ends at its last
use rather than at scope close, so&mut self.afollowed by
&mut self.b(with no use of the first borrow after the second
begins) is now accepted. - Arena escape detection: returning a value that derives from
a locally-declared*Arenais a compile error
(arena-escape). Arenas passed in as fn params are unchanged. - Spawn capture lifetime:
spawn f(p)wherepderives from
a local arena is now a compile error
(spawn-arena-escape). Copy the data out (let x = *p;) or
hand the spawn task a longer-lived arena. - Free-then-use detection on methods: reading a binding after
x.free()errors withuse-after-freeregardless of whether
xwas a*Vector,*Arena, or any other type whose.free()
reclaims its backing memory.
Runtime
- TLS handshake honours a configurable timeout (
set_tls_timeout
default 5 s, override viaListener::accept_raw+attach).
Was blocking the accept loop indefinitely whenever a client
opened a TCP conn and then never wrote the ClientHello. __glide_fs_sizereturnsi64matching the Glide-side extern
shape; the previous 32-bit return overflowed at 2 GiB.
Standard library
stdlib::regex— a pure-Glide PCRE-like engine (classes, quantifiers,
groups, anchors, alternation).stdlib::log— a structured leveled logger (rotating files, syslog,
JSON / key-value output) plusprintln!-style level macrosinfo!/
warn!/error!/debug!/trace!/fatal!. One
import stdlib::log::*;brings the runtime fns and the macros; a bare value
(info!(x)) is wrapped in"{}"automatically.@loggedreports values + timing: the entry line interpolates the actual
argument values, the exit line adds the return value and elapsed time
(> add(4, 6)/< add -> 10 (981.2us)).@tracestays a lightweight
enter/exit flow marker. Level via@logged(info).
Diagnostics
- Aggressive semantic checks: unknown function / name / method /
field / type-in-annotation, wrong argument count, and argument-type
mismatch are now reported for bare fns,Type::method, and instance
methods (including inside proc-macro expansions). - Exact spans: every diagnostic underlines the precise offending
token (the method name, the field, the type, the argument) instead
of an approximate one-character mark at the expression start.
Tooling
- Plug-and-play cross-compile: the target sysroot is auto-fetched
onglide build --target=..., atargetfield inglide.glide
sets a default, and the linker only pulls the heavy libs the program
actually references.glide target list/addmanage sysroots. - LSP: enforces visibility (unknown symbols are flagged live, as
inglide check), completes macros and members, jumps to a
proc-macro definition on goto, and shows inferred-type hints. - Manifest (
glide.glide) awareness: the manifest is parsed for
its fields but never compiled, so the LSP andglide checknow skip
semantic analysis on it (no more falseunknown type Package), while
still surfacing parse errors. Completion is manifest-aware too —
Package+ its fields at the right spots,vec_of, and
Dep::path/Dep::gitinside the dependency list. Field completion
is progressive: fields already written drop off the list, and a value
slot (deps: ...) offersvec_ofrather than field names. A
target:value slot completes the cross-compile triples
(x86_64-linux-musl,aarch64-macos,x86_64-windows-gnu, …). Hover
over any manifest symbol (a field,Package,vec_of,Dep::path/git)
shows what it is and whether it's required.
Fixes
- proc-macro registry namespaced by kind, so
@trace(the
function-tracing attribute) andtrace!(the logging macro) no
longer overwrite each other.@tracehad silently become a no-op. - Static handler tolerates an unset
cache_control: it was
storing a null and dereferencing it on the next request. - Codegen dedupes the chan SM-handler abort helper across chan
monomorphizations; a program using two or morechan<T>types hit
a duplicate-symbol C error. - Spinner writes progress to stderr, so it no longer corrupts
stdout during C emission.