Skip to content

v0.5.0

Latest

Choose a tag to compare

@github-actions github-actions released this 04 Sep 06:15
· 1 commit to main since this release

Added

  • :string ASCII fast path — both directions of a :string now take
    a typed check-and-store loop while the text is ASCII and hand the same
    bytes to babel at the first char/byte ≥ 128, after a peek at the first
    one so text that is non-ASCII from the start (CJK, say) allocates
    nothing extra. Host-neutral, no wire change, the copy contract of
    BOUNDARY §4 untouched — zero-copy :string stays refused. A 64 KiB
    ASCII round trip drops from ~1 ms to ~0.32 ms on the benchmark host
    (docs/benchmarks.md); non-ASCII text costs what it did. New
    v05.utf8-fastpath-boundary walks the seam (empty, DEL, code 128,
    interior NUL, Latin-1 range, 4-byte chars first/last, fill-pointer and
    base strings) through wordbag's echo on all three hosts, and the bench
    gains an rx "count over 1 MiB" row: a real &str consumer.
  • Releases with audited assets — every v* tag builds the four
    examples in the release profile on each required host (Linux x86-64,
    macOS arm64, Windows x86-64), runs tools/rulisp-audit.sh over each
    (Windows: the script prints SKIP, recorded as a gap in BOUNDARY §12),
    and attaches the twelve blobs, named for load-blob-crate, to a
    GitHub Release whose body is that version's CHANGELOG section.
    make check-versions holds every site that repeats the version to
    one string; docs/releasing.md is the checklist around it.
  • MSRVrust-version = "1.78" in the three crates, checked in CI
    on exactly that toolchain over the macros, the runtime, rulisp and
    the code the macros generate for wordbag.
  • Linux aarch64SBCL / Linux aarch64 (best-effort) on GitHub's
    arm runners: the loader's aarch64 paths (the target check, the blob
    suffix) execute for the first time. Promotion follows the written
    procedure; the linux-arm64 release asset comes with it.
  • docs.rs front door — the three macros document the full attribute
    grammar and the closed type vocabulary, every public item in rulisp
    has a doc, the crate-level example is a compiled doctest, and CI builds
    the docs with missing_docs and broken links as errors.
  • Docstrings, describe, and :doc — the REPL front door. Every
    generated function and handle class now has a docstring synthesized
    from the manifest (the Lisp call shape, the Rust signature, and which
    condition an Err becomes); (describe crate) prints where the crate
    came from, its generation, versions, dump hook, handle classes and every
    export's signature. A glue crate's /// comments travel too: the macros
    put them in the manifest as :doc (an enhancement key — older loaders
    ignore it) and they lead the docstring. #. inside a :doc is text,
    never code: the loader's reader runs with *read-eval* off.
  • :rulisp-version in the manifest, and the key-class rule (BOUNDARY
    §11): a load-bearing manifest key raises :schema; an enhancement key
    rides the ignore-unknown-keys rule. Every crate now records the rulisp
    it was built with, and a loader whose major.minor is older signals
    rulisp-version-skew (a style-warning) and loads anyway. Stated
    plainly, because this rule is new: a crate built with 0.4 or later that
    declares on_dump loads cleanly on a 0.3 loader with its dump hook
    silently dropped — :on-dump predates the rule and stays at :schema 1,
    since a retroactive bump would refuse every newer crate on the 0.4.0
    loaders that support it fully. Upgrade the loader.
  • docs/stability.md — what is stable and what 1.0 will promise: the
    four versioned surfaces (Rust API, the 32-symbol Lisp API, the manifest
    schema, the C ABI) and what breaks each; semver and deprecation policy;
    host support defined as the required CI matrix with a written
    promotion/demotion procedure; the manifest key-class rule; the 1.0 exit
    criteria; the Quicklisp prerequisites. CI now proves the system loads
    with no cargo on PATH.

Fixed

  • Docstrings named a symbol that does not exist — for a
    Result<_, Error> export the synthesized "Signals:" line said
    <crate>:rust-error; the condition is rulisp:rust-error itself.
    describe listed a ///-documented export by its first doc line
    instead of its call shape; it now prints the call shape for every
    export. Both surfaced when the docs audit compared usage.md's
    transcript with the loader's real output.
  • Audit false positive on macOStools/rulisp-audit.sh matched an
    inner _signal (_dispatch_semaphore_signal, imported by every macOS
    artifact) as a signal import; only a leading underscore is Mach-O's now,
    and the self-test checks the pattern both ways.
  • On CCL, lending a buffer to Rust stopped the world. CFFI's
    with-pointer-to-vector-data is ccl:with-pointer-to-ivector there,
    whose body runs under without-gcing — so every :string, :bytes
    and :vec argument suspended garbage collection for every thread for
    the whole export, callbacks included (measured: 0 collections
    completed on another thread during a 600 ms borrow; ~30 unpinned). The
    loader now pins only long enough to memcpy into a heap buffer on CCL
    and lends the copy. SBCL keeps the zero-copy borrow; ECL's pin never
    inhibited GC. v05.pin-does-not-stop-the-world proves it on all three.

Changed

  • Docs claim audit — every capability, host and performance claim in
    README and the docs pages (371 of them) now has a citation in
    docs/claims.md or was corrected: the handle bullet (a second free is
    refused, a racing free is deferred), "Scope (v0.1)" and the stale
    "non-SBCL image dump" out-list, the quickstart's error-class rule and
    its ~50 ns figure, usage.md's :target-check story and its Quicklisp
    mention, benchmarks.md's 16× comparison, installation.md's
    cargo-not-found and Windows cache-path rows. One support table (README
    §Status) equals the required CI matrix; benchmarks.md carries SBCL,
    CCL and ECL columns. CI now also loads rulisp from Quicklisp's
    local-projects and load-blob-crates a downloaded release asset, as
    the pages instruct.
  • The fuzzers can fail now. m4h.thread-race and
    m4h.random-op-sequence asserted only "no unexpected condition"; a
    leaked in-flight count or a free that never reached Rust passed. Both
    now reconcile every generation's live-handle and live-allocation
    counters at the end (captured as wrapper closures, so generations
    reloaded mid-run reconcile against their own library copy), take their
    seed from RULISP_FUZZ_SEED (a workflow_dispatch input in CI) and
    print it on failure. Verified by mutation: with half of all frees
    skipped, the race fuzzer reports the leak. New m4h.reload-under-load
    proves BOUNDARY §4's cross-reload claim — strings round-tripped by four
    threads across three live reloads are released through their own
    generation's dealloc; every generation ends at zero.
  • The fetch suite runs in CI (SBCL/Linux and CCL/Linux required; macOS
    best-effort) — the 23 tests BOUNDARY §12 cites had only ever run on the
    maintainer's machine. Its first run on CCL fixed two host assumptions in
    the tests themselves.