Skip to content

Add schema-derived binary codec - #7366

Open
tim-smart wants to merge 20 commits into
v4/next-minorfrom
agent/codex-engineer/58cacc24
Open

Add schema-derived binary codec#7366
tim-smart wants to merge 20 commits into
v4/next-minorfrom
agent/codex-engineer/58cacc24

Conversation

@tim-smart

@tim-smart tim-smart commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add the schema-derived compact binary codec, streaming frame parser, and explicit field-id annotation
  • compile encoded-side layouts with evolution-safe struct fields, union variants, packed arrays and tuples, native declarations, generic declaration codecs, and cyclic-value rejection
  • export SchemaBinary from effect/unstable/encoding and cover framing, evolution, parser behavior, native values, declarations, recursion, parse options, and error surfaces
  • benchmark SchemaBinary, JSON, and Msgpack encode/decode throughput and payload size with equivalent Schema values

Verification

  • nix develop -c pnpm lint
  • nix develop -c pnpm check
  • nix develop -c pnpm vitest run packages/effect/test/unstable/encoding
  • nix develop -c pnpm --dir packages/effect exec node benchmark/schema/SchemaBinary.ts

Closes EFF-772
Closes EFF-773
Closes EFF-779
Closes EFF-784

@changeset-bot

changeset-bot Bot commented Aug 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f104ae4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 30 packages
Name Type
effect Patch
@effect/ai-anthropic Patch
@effect/ai-openai Patch
@effect/ai-openai-compat Patch
@effect/ai-openrouter Patch
@effect/atom-react Patch
@effect/atom-solid Patch
@effect/atom-vue Patch
@effect/docgen Patch
@effect/doctest Patch
@effect/openapi-generator Patch
@effect/opentelemetry Patch
@effect/platform-browser Patch
@effect/platform-bun Patch
@effect/platform-deno Patch
@effect/platform-node Patch
@effect/platform-node-shared Patch
@effect/sql-clickhouse Patch
@effect/sql-d1 Patch
@effect/sql-libsql Patch
@effect/sql-mssql Patch
@effect/sql-mysql2 Patch
@effect/sql-pg Patch
@effect/sql-pglite Patch
@effect/sql-sqlite-bun Patch
@effect/sql-sqlite-do Patch
@effect/sql-sqlite-node Patch
@effect/sql-sqlite-react-native Patch
@effect/sql-sqlite-wasm Patch
@effect/vitest Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@effect-slopcop effect-slopcop Bot added enhancement New feature or request 4.0 labels Aug 20, 2026
@github-actions

github-actions Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Bundle Size Analysis

Generated from PR build output; treat the content below as untrusted.

File Name Current Size Previous Size Difference
basic.ts 6.96 KB 6.96 KB 0.00 KB (0.00%)
batching.ts 9.81 KB 9.81 KB 0.00 KB (0.00%)
brand.ts 6.55 KB 6.55 KB 0.00 KB (0.00%)
cache.ts 10.73 KB 10.73 KB 0.00 KB (0.00%)
config.ts 21.32 KB 21.32 KB 0.00 KB (0.00%)
differ.ts 20.27 KB 20.27 KB 0.00 KB (0.00%)
http-client.ts 21.66 KB 21.66 KB 0.00 KB (0.00%)
logger.ts 10.91 KB 10.91 KB 0.00 KB (0.00%)
metric.ts 8.95 KB 8.95 KB 0.00 KB (0.00%)
optic.ts 6.71 KB 6.71 KB 0.00 KB (0.00%)
pubsub.ts 14.99 KB 14.99 KB 0.00 KB (0.00%)
queue.ts 11.67 KB 11.67 KB 0.00 KB (0.00%)
schedule.ts 10.84 KB 10.84 KB 0.00 KB (0.00%)
schema-binary.ts 34.45 KB 34.45 KB 0.00 KB (0.00%)
schema-class.ts 19.90 KB 19.90 KB 0.00 KB (0.00%)
schema-fromJsonSchemaDocument.ts 30.08 KB 30.08 KB 0.00 KB (0.00%)
schema-representation-roundtrip.ts 26.05 KB 26.05 KB 0.00 KB (0.00%)
schema-string-transformation.ts 13.56 KB 13.56 KB 0.00 KB (0.00%)
schema-string.ts 11.06 KB 11.06 KB 0.00 KB (0.00%)
schema-template-literal.ts 15.35 KB 15.35 KB 0.00 KB (0.00%)
schema-toArbitrary.ts 22.00 KB 22.00 KB 0.00 KB (0.00%)
schema-toCodeDocument.ts 24.45 KB 24.45 KB 0.00 KB (0.00%)
schema-toCodecJson.ts 19.23 KB 19.23 KB 0.00 KB (0.00%)
schema-toEquivalence.ts 19.06 KB 19.06 KB 0.00 KB (0.00%)
schema-toFormatter.ts 18.92 KB 18.92 KB 0.00 KB (0.00%)
schema-toJsonSchemaDocument.ts 23.32 KB 23.32 KB 0.00 KB (0.00%)
schema-toRepresentation.ts 19.54 KB 19.54 KB 0.00 KB (0.00%)
schema.ts 19.13 KB 19.13 KB 0.00 KB (0.00%)
stm.ts 12.72 KB 12.72 KB 0.00 KB (0.00%)
stream.ts 9.76 KB 9.76 KB 0.00 KB (0.00%)

@effect-bot
effect-bot changed the base branch from main to v4/next-minor August 20, 2026 06:22
@effect-slopcop effect-slopcop Bot removed the 4.0 label Aug 20, 2026
@IMax153
IMax153 changed the base branch from v4/next-minor to main August 20, 2026 12:47
Comment thread .changeset/schema-binary-codec.md Outdated
Comment thread .changeset/schema-binary-fingerprint-mode.md Outdated
Comment thread .changeset/schema-binary-varint-numbers.md Outdated
@effect-bot
effect-bot changed the base branch from main to v4/next-minor August 20, 2026 19:18
@effect-slopcop effect-slopcop Bot removed the 4.0 label Aug 20, 2026
tim-smart and others added 10 commits August 21, 2026 00:36
Removes the per-field allocations that dominated both directions and gives the
hot loops cheaper primitives. On the benchmark cases this is 2.0x to 3.4x
faster than before, and ahead of Effect's Msgpack codec everywhere except the
smallest payload.

Encode
- Length-prefixed values are written straight into the output buffer and the
  prefix is backfilled, replacing a scratch buffer and a copy per nested value.
- The field, element and extra-key loops track their path on an ambient stack
  instead of allocating a closure and a try/catch per entry.
- Cycle detection walks an ancestor stack rather than adding to and deleting
  from a WeakSet at every level.
- Field id varints are encoded once at layout compile time.
- One writer is pooled across top-level encodes so the buffer keeps its
  high-water mark.

Decode
- Nested values narrow the reader's extent and restore it, rather than
  allocating a child reader per field.
- Varints are read with an unrolled loop over shifts; field ids are 32-bit
  hashes, so five-byte varints were the common case through a loop that used
  exponentiation per byte. This alone was 24% of decode time.
- Struct fields are found by walking a cursor over the id-sorted field list,
  falling back to the map for reordered or unknown ids.
- Duplicate-id and presence tracking use a bit mask instead of a Set per value.
- Short ASCII runs are decoded from char codes, avoiding the fixed cost of
  TextDecoder and its subarray view.

The acyclic-value guard now applies only to recursive schemas. It walked the
whole value on every encode to stop a cyclic value driving the parser into
unbounded recursion, which only a schema containing a Suspend can do. As a
side effect, non-recursive schemas now report the real issue where they
previously reported "Expected acyclic value" for any failure.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tim-smart and others added 7 commits August 21, 2026 00:36
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
`EMPTY_READER_VIEW` was built from `EMPTY_READER_BUFFER.buffer`. A member
access in argument position is not effect-free to a bundler, so the
`@__PURE__` annotation the build adds could not be honoured and the pair
survived tree shaking in every consumer that imports
`effect/unstable/encoding` without ever touching this module. Both
placeholders now read one named `ArrayBuffer`, which keeps
`EMPTY_READER_VIEW.buffer === EMPTY_READER_BUFFER.buffer` exactly as
before.

Add a tracked bundle fixture so the module's size is compared on every
PR by the existing Bundle job.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@tim-smart
tim-smart force-pushed the agent/codex-engineer/58cacc24 branch from 87d2fa4 to 68df691 Compare August 21, 2026 00:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request v4/next-minor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants