1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
[]
= "obj-db"
= "Embedded document database. Stable file format, full ACID, single-file portability."
= true
= true
= true
= true
= true
= true
= "https://github.com/uname-n/obj"
= "https://docs.rs/obj-db"
= "README.md"
= ["database", "embedded", "document", "acid", "storage"]
= ["database", "database-implementations", "data-structures"]
# docs.rs (release-review #38): build the docs with every feature on so
# the rendered API includes the serde / tracing / compression /
# encryption / async surface — all features are off by default, so
# without this docs.rs would show only the bare baseline.
[]
= true
= ["--cfg", "docsrs"]
# Package is published to crates.io as `obj-db`
# The library name stays `obj` so downstream users write `use obj::Db`
# — they just `cargo add obj-db` to pull it in.
[]
= "obj"
[]
= { = "../obj-core", = "1.1.2" }
# M9: `obj-derive` is re-exported as `obj::Document` (proc-macro) so
# users write `#[derive(obj::Document)]` against this single crate.
= { = "../obj-derive", = "1.1.2" }
# Phase 2A (issue #6): `serde` is an opt-in feature on obj-db. When
# the `serde` feature is enabled, public obj-db types derive
# `Serialize` + `Deserialize` and the two traits are re-exported from
# the crate root. `obj-core` already depends on `serde` unconditionally
# (postcard needs it on disk), so flipping this feature on costs
# essentially nothing at the binary level — it only widens the public
# API surface. MIT OR Apache-2.0.
= { = "1", = ["derive"], = true }
# Phase 2B (issue #7): `tracing` is opt-in. When enabled, obj-db
# emits structured spans around `Db::open`, transaction begin /
# commit / rollback, `Query::fetch` / `count`, `integrity_check`,
# and the obj-core pager checkpoint. The dependency is optional so
# `cargo build --no-default-features` adds no new transitive deps.
# Apache-2.0 OR MIT.
= { = "0.1", = true }
# Phase 5 (issue #10): `blocking` is the runtime-agnostic
# blocking-task executor used by the opt-in `async` feature. It
# spawns a lazily-initialised thread pool and exposes
# `blocking::unblock(closure).await` — compatible with Tokio,
# async-std, smol, and any other async runtime. The dependency is
# optional so `cargo build --no-default-features` adds no new
# transitive deps. Apache-2.0 OR MIT.
= { = "1", = true }
# #87 (perf): OPTIONAL, NON-DEFAULT. `mimalloc` is only pulled in by
# the `fast-alloc` feature, which exists purely so the bench binaries
# can register a `#[global_allocator]` for an apples-to-apples
# allocator A/B. The `obj` LIBRARY never registers a global allocator
# (a library must not force a process-global allocator on downstreams
# — issue #87 guardrail); the static lives only in the bench binary.
# `mimalloc` is the workspace's first vendored-C build dep, so it is
# gated behind a feature that is off by default: the baseline build,
# public-api surface, Miri run, and `forbid-unsafe` posture are all
# unchanged unless `--features fast-alloc` is passed explicitly.
= { = "0.1", = true }
[]
# Phase 2A (issue #6): no default features. Keeping this section
# explicit makes the intent visible to readers and to `cargo metadata`.
= []
# Opt-in: derive `serde::Serialize` + `serde::Deserialize` on the
# public obj-db types and re-export the two traits from the crate
# root. Pure additive surface — no format-byte impact.
= ["dep:serde"]
# Phase 2B (issue #7): emit `tracing` spans around the obj-db
# observability surface. Propagates to obj-core so the pager's
# checkpoint span lights up under the same flag. Off by default —
# zero span overhead in the baseline build.
= ["dep:tracing", "obj-core/tracing"]
# Phase 3 (issue #8): LZ4 per-page page compression. Propagates to
# obj-core. Off by default. v1.0 writers always stamp
# `format_minor = 2`; compression is signalled per-page by a flag
# bit, not by the minor version. A build WITHOUT this feature reads
# uncompressed files normally and refuses any file that contains an
# LZ4-compressed page with `Error::FormatFeatureUnsupported`.
= ["obj-core/compression"]
# Phase 4 (issue #9): ChaCha20-Poly1305 per-page at-rest
# encryption. Propagates to obj-core. Off by default. v1.0 writers
# always stamp `format_minor = 2`; encryption is signalled by
# `feature_flags` bit 1 in the page-0 header, not by the minor. A
# build WITHOUT this feature refuses to open an encrypted file with
# `Error::FormatFeatureUnsupported`.
= ["obj-core/encryption"]
# Phase 5 (issue #10): runtime-agnostic async surface mirroring
# the blocking `Db` / `Collection` / `Query` API behind a new
# `obj::asynchronous` module. Work is routed through the
# `blocking` crate's process-wide thread pool — every async
# method spawns its body via `blocking::unblock(...).await`, so
# the surface composes with Tokio, async-std, smol, and any
# other runtime without per-runtime sub-features. Off by default
# — the baseline build has zero new transitive deps and zero
# async overhead. The blocking surface (`Db`, `Collection`,
# `Query`, `WriteTxn`, `ReadTxn`) is untouched: the async types
# are pure additions.
= ["dep:blocking"]
# #87 (perf): opt-in `mimalloc` `#[global_allocator]`. NON-DEFAULT.
# Only the bench binaries register the allocator (behind
# `#[cfg(feature = "fast-alloc")]`); the `obj` library does NOT — a
# library forcing a process-global allocator collides with downstream
# applications. Enable with `cargo bench -p obj-db --features
# fast-alloc` to A/B the allocator against the system one. Off by
# default keeps the baseline dep tree free of the vendored-C build.
= ["dep:mimalloc"]
[]
# `tempfile` provides RAII temp directories for the integration
# tests. MIT OR Apache-2.0.
= "3"
# `trybuild` drives compile-fail tests for the `#[derive(Document)]`
# proc-macro (M9 #79). MIT OR Apache-2.0.
= "1"
# `serde` derive macros for the integration test's Document
# implementations. MIT OR Apache-2.0. Cargo permits the same crate in
# both `[dependencies]` (optional, gating the `serde` feature) and
# `[dev-dependencies]` (always-on, so integration tests compile
# without `--features serde`).
= { = "1", = ["derive"] }
# Phase 2A (issue #6): the new `serde_feature` integration test
# round-trips public types through JSON. MIT OR Apache-2.0.
= "1"
# Phase 2B (issue #7): the new `tracing_feature` integration test
# attaches a capturing `Layer` to assert the opt-in `tracing`
# feature wires the six spans. MIT.
= "0.3"
# `criterion` for the M6 #48 concurrent-reader scaling bench.
# MIT OR Apache-2.0. Default features disabled to mirror the M4
# bench convention; single-threaded measurement is sufficient here
# because the bench manages its own thread fan-out.
= { = "0.5", = false, = ["cargo_bench_support"] }
# Deterministic PRNG for the bench's id-sampling so two runs of
# the bench against the same data set produce comparable numbers.
= "0.9"
= "0.9"
# M10 #82: schema-registry tests hand-encode v1 / v2 payloads via
# postcard to drive `Dynamic::from_postcard_bytes(...)`. The
# obj-core crate already pins the same major; no version skew.
# `default-features = false` mirrors obj-core (issues #39/#68): the
# tests only use the `to_allocvec` / `from_bytes` alloc path, so
# dropping postcard's `heapless-cas` default keeps heapless 0.7 +
# atomic-polyfill (RUSTSEC-2023-0089) out of the locked dev tree too.
= { = "1", = false, = ["alloc"] }
# `obj-core` is already a normal dependency above; the M7 #61
# `index_range` bench reaches into the order-preserving key encoder
# (`obj_core::index::encode_field`) to build half-open range bounds.
# A `dev-dependencies` entry is unnecessary because the public dep
# already exposes the path.
# Phase 5 (issue #10): drive the async wrapper from a real runtime
# inside the integration tests. Both runtimes ride the same
# `blocking` crate via the opt-in `async` feature — the tests
# exercise both to prove the runtime-agnostic invariant. MIT.
= { = "1", = ["rt", "rt-multi-thread", "macros"] }
# The second runtime is `smol`: async-std was discontinued
# (RUSTSEC-2025-0052) and its own README points at smol as the
# replacement. smol has no test-attribute macro, so the companion
# test drives it via `smol::block_on`. MIT/Apache-2.0.
= "2"
[[]]
# M6 issue #48: N-reader scaling benchmark. `harness = false`
# lets criterion own the test main.
= "concurrent_reads"
= false
[[]]
# M7 issue #61: `find_unique` warm-cache latency benchmark.
= "index_lookup"
= false
[[]]
# M7 issue #61: `index_range` vs full-scan ratio benchmark.
= "index_range"
= false
[[]]
# M8 issue #69: `Db::all::<T>()` 100k-doc collection-scan benchmark
# (M8 exit gate, perf side). `OBJ_BENCH_ENFORCE=1` upgrades the
# informational TARGET_MS check to a hard failure.
= "collection_scan"
= false
[[]]
# M11 issue #94: `Db::integrity_check` 1 GB benchmark (M11 exit
# gate, perf side). Asserts the integrity walk completes within an
# order of magnitude of a `wc -c` proxy derived from the on-disk
# file size. `OBJ_BENCH_ENFORCE=1` upgrades the informational
# print to a hard failure.
= "integrity_1gb"
= false
[[]]
# M14 issue #119: design.md 8-row perf-table reproduction harness.
# Runs every row under criterion + emits a markdown table to stdout
# and `target/criterion/perf_table/perf_table.md`.
# `OBJ_BENCH_ENFORCE=1` upgrades the print to a hard gate (each row
# must stay within 10× of its design.md target).
= "perf_table"
= false
[[]]
# Lean human-facing perf-iteration bench (issue #78). NOT a CI gate
# bench — pure criterion, short windows, ~256-doc populate. Use
# `--save-baseline` / `--baseline` to compare across changes.
= "quick"
= false
[]
= true