Skip to content

Glide v0.2.0

Choose a tag to compare

@Murilinho145SG Murilinho145SG released this 25 May 07:34
· 125 commits to main since this release

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
    spellings int / uint / long / ulong / float are retired as type names
    using one is an error with a hint to the canonical replacement. i128/u128
    are native (__int128); i256/u256 are a first-class software 4×u64 struct
    with operators dispatched to runtime helpers, built via u256::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::MAX was showing -1).
  • Anonymous tuples: (A, B, ...) as a first-class structural type — tuple
    literals (a, b), positional access t.0 / t.1 (nested t.0.1 too),
    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 the struct Name(field: T) tuple-struct
    sugar (which stays the way to name a value type).

Compiler

  • Flexible main signatures: fn main(), fn main() -> i32, and
    fn main() -> !T are 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) fixes v to Vector<int>, so a later v.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
    main with the router setup, and routes!(r). Method-aware router with
    :param / *wildcard segments.
  • 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 via sendfile / 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 @leaf coroutine runs inline on its worker
    (~192 B/task). http_listen_workers / the router use a state-machine fast
    path by default (≈95% of Axum); @leaf is 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_unpark went 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_diag lets a pass emit custom lints (location + code + severity)
    that get the same rendering and @allow suppression 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 --lib scaffolds a
    library as src/<name>.glide.
  • Git deps accept file:// and git:// remotes.
  • The manifest parses author / license / description / repository
    (informational) and they're scaffolded into a new project.
  • glide check with 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 the if os_is_windows() { ... } else { spawn ... } branch in http_listen, which on macOS/BSD sent
    every accepted conn through a sync read that pinned its
    worker thread.
  • AArch64 (ARM64) context switch__glide_ctx_switch now
    carries an stp/ldp backend that saves x19-x30 + d8-d15. Plus
    a yield (vs pause) hint in the spin loops and the
    aarch64-linux-musl triple 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-musl resolves.
  • 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_workers and
    Router::listen_workers now 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_async issue OVERLAPPED ops
    against WSARecv / WSASend; a dedicated reactor thread
    drains GetQueuedCompletionStatus and unparks the issuing
    coro. http_listen now 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_ACTIVE etc).
  • cc invocation on Windows no longer wraps everything in an
    outer "...". The wrap was meant to handle a quoted cc path
    with spaces, but it broke cmd.exe /c parsing whenever the
    inner argv already had quoted paths, leaving collect2 with the
    raw .c file as a "linker input" instead of a compiled .o.
  • New TLS flag __glide_is_main_tls set on the C main thread.
    __glide_spawn from a foreign pthread (e.g. an http_listen
    accept loop running on its own spawn_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.a followed 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 *Arena is a compile error
    (arena-escape). Arenas passed in as fn params are unchanged.
  • Spawn capture lifetime: spawn f(p) where p derives 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 with use-after-free regardless of whether
    x was 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 via Listener::accept_raw + attach).
    Was blocking the accept loop indefinitely whenever a client
    opened a TCP conn and then never wrote the ClientHello.
  • __glide_fs_size returns i64 matching 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) plus println!-style level macros info! /
    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.
  • @logged reports 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)). @trace stays 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
    on glide build --target=..., a target field in glide.glide
    sets a default, and the linker only pulls the heavy libs the program
    actually references. glide target list/add manage sysroots.
  • LSP: enforces visibility (unknown symbols are flagged live, as
    in glide 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 and glide check now skip
    semantic analysis on it (no more false unknown 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::git inside the dependency list. Field completion
    is progressive: fields already written drop off the list, and a value
    slot (deps: ...) offers vec_of rather 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) and trace! (the logging macro) no
    longer overwrite each other. @trace had 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 more chan<T> types hit
    a duplicate-symbol C error.
  • Spinner writes progress to stderr, so it no longer corrupts
    stdout during C emission.