Skip to content

Events, slice 4b — via schema range dispatch (v.., ..v, v1..v2, _) #990

Description

@accuser

Part of #936. Follows #985 (slice 4, shipped).

Background

Slice 4 (#985) shipped via schema(N) literal-value dispatch, deliberately
narrowing out range patterns: design/bynk-design-notes.md's original
worked example uses them (via schema(2..) for "version 2 or later"), but
no range-pattern syntax existed anywhere in bynk at the time, so ranges
were split to this unfiled slice.

This proposal adds the range half: via schema(v..), via schema(..v),
via schema(v1..v2), and an explicit via schema(_) wildcard (redundant
with omitting the clause entirely, but useful for symmetry once ranges
exist — a service listing several sibling via schema(...) clauses across
a family of subscribers may want every case written explicitly rather than
one left as "no clause").

Design

Bounds are inclusive on both ends, matching the one existing integer-
range concept in bynk: the InRange(lo, hi) refinement predicate lowers to
receiver >= lo && receiver <= hi (bynk-emit/src/emitter.rs), described
as "must be in range [lo, hi]" — bracket notation, inclusive. via schema(v1..v2) follows the identical convention: v1 <= schemaVersion <= v2. via schema(v..) is schemaVersion >= v; via schema(..v) is
schemaVersion <= v.

Grammar: extends schema_dispatch_clause's argument position (today:
optional("-") number_literal only) to also admit:

  • number_literal ".." (open-above)
  • ".." number_literal (open-below)
  • number_literal ".." number_literal (closed)
  • "_" (wildcard, matches any version — same as omitting the clause)

Reuses the .. (DotDot) token slice 1 already added (previously only a
record-pattern's rest marker) and the _ (Underscore) token already used
by match-pattern wildcards — no new lexer tokens.

AST: SchemaVersionPattern (today: Literal(i64) only) gains three
variants — OpenAbove(i64), OpenBelow(i64), Closed(i64, i64) — plus
Wildcard. Additive to the enum, per slice 4's own ADR naming this as the
expected extension point.

Checker: each bound independently must be a positive Int literal
(the existing bynk.event.bad_schema_dispatch rule, unchanged). A new
check for Closed(lo, hi): lo > hi is an always-empty range — reject it
as malformed (mirrors InRange's own inconsistent-bounds check, "exactly
one error" per its own test) rather than silently accepting a clause that
can never match.

Emitter: the guard's comparison operator changes per variant —
=== (Literal, unchanged), >= (OpenAbove), <= (OpenBelow), >= lo && <= hi (Closed), and no guard at all for Wildcard (identical to the
no-clause case — the synthetic-envelope-parameter plumbing from slice 4
still applies whenever any via schema(...) is written, including
_, in case a sibling subscriber in the same family relies on it being
present for a different variant).

No new ambiguity check. Slice 4's own policy continues unchanged:
sibling subscribers with overlapping or gapped range coverage are not
diagnosed, for the identical reason slice 1's payload pattern and slice
4's literal dispatch aren't.

Verification

Positive behavioural test extending slice 4's own (events_schema_dispatch_ behaviour.rs): compile at three or more schema versions, assert each
lands in the correct one of via schema(1), via schema(2..4),
via schema(5..), via schema(_) (four sibling subscribers, one compile
per version tested). Negative fixture for the new lo > hi diagnostic.
Regression: existing literal-only fixtures/tests unaffected.

Metadata

Metadata

Assignees

No one assigned

    Labels

    acceptedAn accepted proposal — approved to buildproposalAn increment proposal — the sign-off artefact; accepted = approval to build

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions