Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/test-all-features.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,14 @@ jobs:
- name: Test all features (host)
run: cargo test --workspace --all-features

- name: Check no_std (bijou32)
run: cargo check --package bijou32 --no-default-features

- name: Check no_std (bijou64)
run: cargo check --package bijou64 --no-default-features

- name: Check no_std (bijou128)
run: cargo check --package bijou128 --no-default-features

- name: Check wasm32 (workspace)
run: cargo check --workspace --target wasm32-unknown-unknown
42 changes: 28 additions & 14 deletions .github/workflows/test-wasm.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name: Test Wasm

# Three layers of wasm coverage:
# Three layers of wasm coverage, each run for every wasm crate in the
# workspace (bijou32_wasm, bijou64_wasm, bijou128_wasm):
#
# 1. `wasm-pack test --node` exercises the Rust ↔ wasm-bindgen boundary
# on the wasm32-unknown-unknown target inside Node.js. Fast, no
Expand Down Expand Up @@ -32,12 +33,15 @@ env:
jobs:
# Fast Rust-side integration tests on wasm32 in Node.js.
# macOS included so we catch any darwin-specific wasm-bindgen quirks.
# Matrix over all three wasm crates so a regression in one is visible.
wasm-pack-node:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
crate: [bijou32_wasm, bijou64_wasm, bijou128_wasm]

name: wasm-pack test ${{ matrix.crate }} (${{ matrix.os }})
runs-on: ${{ matrix.os }}

steps:
Expand All @@ -57,15 +61,25 @@ jobs:
with:
tool: wasm-pack@0.14.0

- name: wasm-pack test --node
run: wasm-pack test --node bijou64_wasm
- name: wasm-pack test --node ${{ matrix.crate }}
run: wasm-pack test --node ${{ matrix.crate }}

# JS-package tests against the wasm-bodge `dist/` output: Mocha
# exercises the Node entrypoint; Playwright exercises the browser
# entrypoint across chromium / firefox / webkit. Linux only — macOS
# Playwright runs work but are slow and the bug surface is similar
# enough that ubuntu-latest suffices for CI.
#
# Matrix over all three wasm crates: each one ships its own
# `package.json`, `dist/`, and Playwright config, so a regression in
# one crate's wasm-bodge build doesn't mask another's.
js-package:
strategy:
fail-fast: false
matrix:
crate: [bijou32_wasm, bijou64_wasm, bijou128_wasm]

name: JS-package tests ${{ matrix.crate }}
runs-on: ubuntu-latest
env:
# Force playwright to test all three engines on CI.
Expand All @@ -86,7 +100,7 @@ jobs:
with:
node-version: 22
cache: 'pnpm'
cache-dependency-path: bijou64_wasm/pnpm-lock.yaml
cache-dependency-path: ${{ matrix.crate }}/pnpm-lock.yaml

- name: Setup Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
Expand Down Expand Up @@ -117,17 +131,17 @@ jobs:
--rev 58e0d9b2c3b749d81df7813e380432d04a904f23 \
--locked

- name: Build bijou64_wasm with wasm-bodge
working-directory: bijou64_wasm
- name: Build ${{ matrix.crate }} with wasm-bodge
working-directory: ${{ matrix.crate }}
run: wasm-bodge build

- name: Install JS dependencies
working-directory: bijou64_wasm
working-directory: ${{ matrix.crate }}
run: pnpm install --frozen-lockfile

- name: Read Playwright version
id: playwright-version
working-directory: bijou64_wasm
working-directory: ${{ matrix.crate }}
run: |
version=$(pnpm list @playwright/test --json | \
jq -r '.[0].devDependencies["@playwright/test"].version')
Expand All @@ -142,26 +156,26 @@ jobs:

- name: Install Playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
working-directory: bijou64_wasm
working-directory: ${{ matrix.crate }}
run: pnpm exec playwright install --with-deps chromium firefox webkit

- name: Install Playwright system dependencies
if: steps.playwright-cache.outputs.cache-hit == 'true'
working-directory: bijou64_wasm
working-directory: ${{ matrix.crate }}
run: pnpm exec playwright install-deps

- name: Run Node JS-package tests (Mocha)
working-directory: bijou64_wasm
working-directory: ${{ matrix.crate }}
run: pnpm run test:js:node

- name: Run browser JS-package tests (Playwright)
working-directory: bijou64_wasm
working-directory: ${{ matrix.crate }}
run: pnpm run test:js:browser

- name: Upload Playwright report on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: playwright-report
path: bijou64_wasm/playwright-report/
name: playwright-report-${{ matrix.crate }}
path: ${{ matrix.crate }}/playwright-report/
retention-days: 7
44 changes: 44 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
[workspace]
resolver = "3"
members = [
"bijou32",
"bijou32_wasm",
"bijou64",
"bijou64_wasm",
"bijou128",
"bijou128_wasm",
]

[workspace.package]
Expand All @@ -16,8 +20,12 @@ authors = [

[workspace.dependencies]
# Internal crates
bijou32 = { version = "0.1", path = "bijou32", default-features = false }
bijou32_wasm = { version = "0.1", path = "bijou32_wasm", default-features = false }
bijou64 = { version = "0.2", path = "bijou64", default-features = false }
bijou64_wasm = { version = "0.1", path = "bijou64_wasm", default-features = false }
bijou128 = { version = "0.1", path = "bijou128", default-features = false }
bijou128_wasm = { version = "0.1", path = "bijou128_wasm", default-features = false }

# External crates
arbitrary = "1.4"
Expand Down
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,29 @@ encoding decodes to exactly one value_. The tag byte alone determines
the total length, payloads are big-endian (so lexicographic byte
order matches numeric order), and there is no `std` requirement.

## Crates

| Crate | Integer | Max bytes | Description |
|----------------------------------------|---------|-----------|------------------------------------------------------------|
| [`bijou32`](./bijou32) | `u32` | 5 | The narrowest variant. Tag threshold 252. |
| [`bijou32_wasm`](./bijou32_wasm) | `u32` | 5 | Wasm/JS bindings for `bijou32` (npm package `bijou32`). |
| [`bijou64`](./bijou64) | `u64` | 9 | The reference implementation. Tag threshold 248. |
| [`bijou64_wasm`](./bijou64_wasm) | `u64` | 9 | Wasm/JS bindings for `bijou64` (npm package `bijou64`). |
| [`bijou128`](./bijou128) | `u128` | 17 | Same scheme widened to 128 bits. Tag threshold 240. |
| [`bijou128_wasm`](./bijou128_wasm) | `u128` | 17 | Wasm/JS bindings for `bijou128` (npm package `bijou128`). |

The three width variants are **not wire-compatible** — they use
different tag thresholds (252 vs 248 vs 240) so each can reach its
maximum in the smallest number of bytes. Pick the width that matches
your value domain; don't mix encodings on the same wire without an
out-of-band signal.

The wasm crates also differ in their JS boundary type:

- `bijou32` uses plain JS `number` (since `u32::MAX < Number.MAX_SAFE_INTEGER`)
- `bijou64` and `bijou128` use `bigint`
- `decodeAll` returns `Uint32Array` (bijou32), `BigUint64Array` (bijou64), or `Array<bigint>` (bijou128, since the web platform has no `BigUint128Array`)

## Quick start

```rust
Expand All @@ -22,6 +45,20 @@ assert_eq!(value, 300);
assert_eq!(len, 2);
```

For 32-bit and 128-bit values, the API is identical:

```rust
// 32-bit
let mut buf = Vec::new();
bijou32::encode(300, &mut buf);
assert_eq!(buf, [0xFC, 0x30]);

// 128-bit
let mut buf = Vec::new();
bijou128::encode(500, &mut buf);
assert_eq!(buf, [0xF1, 0x00, 0x04]);
```

## Development

This repository is a Cargo workspace with a Nix flake providing the
Expand Down
33 changes: 33 additions & 0 deletions bijou128/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[package]
name = "bijou128"
version = "0.1.0"
description = "Bijective variable-length encoding for unsigned 128-bit integers"

categories = ["encoding", "no-std"]
keywords = ["varint", "variable-length", "canonical", "bijective"]
readme = "./README.md"

authors.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true

[dependencies]
arbitrary = { workspace = true, optional = true, features = ["derive"] }
bolero = { workspace = true, optional = true, features = ["arbitrary"] }
thiserror = { workspace = true }

[dev-dependencies]
arbitrary = { workspace = true, optional = false, features = ["derive"] }
bijou128 = { path = ".", features = ["bolero"] }
bolero = { workspace = true, features = ["arbitrary"] }
testresult = { workspace = true }

[features]
default = []
arbitrary = ["dep:arbitrary"]
bolero = ["dep:bolero", "arbitrary"]

[lints]
workspace = true
Loading
Loading