Rust core — paginate-core
paginate-core is the pure,
language-agnostic engine behind the whole project. The Python (pypaginate) and
TypeScript (@cyblow/paginate) packages are thin native bindings over it — so this
crate is where the actual algorithms live.
[dependencies]
paginate-core = "0.1"
➡️ API reference: docs.rs/paginate-core — the canonical, auto-published Rust documentation.
What it owns
Everything computational, exactly once:
- Cursor codec —
encode_cursor/decode_cursor, a typed, URL-safe wire format. - Pagination math — offset / pages /
has_next, and the keyset predicate structure. - Filtering — the 20 operators, flat AND/OR, and nested groups (
FilterSpec,FilterGroup,FilterOp). - Sorting — stable multi-key with null placement (
SortSpec,SortDirection,NullsPosition). - Search — token matching and ranked trigram fuzzy scoring (
SearchSpec,TrigramIndex,FuzzyMode). - Text normalization —
normalize_text, shared by search and matching. - The columnar fast path —
Columns, a dense typed projection that accelerates the filter and sort stages.
The public surface is re-exported flat from the crate root
(paginate_core::FilterSpec, never paginate_core::filter::types::FilterSpec), so the
module layout can change without breaking callers.
Design in one sentence
The core speaks only plain data — a small JSON-like Value
enum — has zero binding dependencies, and returns indices (never cloned rows),
so the exact same crate links natively into Python (PyO3) and Node/TypeScript
(napi-rs) and compiles unchanged to WebAssembly. See design.
When to use it directly
- You're building a Rust service and want pagination / filtering / sorting / search with the same semantics (and cursor format) as your Python or TypeScript services.
- You're writing another language binding — wrap this crate rather than re-implementing the engine, and inherit parity for free.
If you're in Python or TypeScript, you don't depend on this crate directly — you
install the pypaginate or
@cyblow/paginate package, which bundles it.
Status
paginate-core is published on crates.io and documented on docs.rs. It is
#![forbid(unsafe_code)], carries #![warn(missing_docs)], and is verified against the
Python codec with byte-identical golden vectors plus property tests — see
design → parity.
Next
- Using the core — the
Valuemodel, feature flags, and a cursor example. - Design — fat core / thin adapters, in depth.
- Performance — where the native boundary pays off (measured).