git-zero-core 0.2.0

Allocation-free no_std Git objects, repositories, packs, zlib and delta primitives
Documentation
# git-zero-core

Allocation-free Git objects, repositories, packs, zlib, and delta primitives.
Safe `no_std` Rust without `alloc`; the caller owns storage, scratch, and I/O.

```toml
[dependencies]
git-zero-core = "0.1.0"
```

`read` enables decoding and repository validation; `write` enables snapshot
construction and encoding. Both are enabled by default. Select only what the
application needs, for example `default-features = false, features = ["read"]`.
The [API reference](https://docs.rs/git-zero-core) describes the public types.
Use [git-zero](https://docs.rs/git-zero) when client or server reexports are useful.

With `write`, `pack::write_indexed_with_scratch` streams a stored-block pack and a Git v2 index
using one caller-owned `pack::IndexEntry` per object and bounded read scratch.
It supports SHA-1/SHA-256, selected object orders, wire CRCs and 64-bit offsets.
Publish the pair only after success: errors invalidate both outputs. Existing
verified entry metadata can be streamed separately with `pack::write_index`.

With `read`, `pack::Decoder` accepts fragmented SHA-1/SHA-256 packs without
retaining a complete pack, object body, or object-count-sized index. The host
supplies a 32 KiB inflate window and arbitrary input/output slices. Events expose
entry headers, body fragments, entry CRCs, plain-object IDs, and the verified
pack checksum. Offset/reference deltas emit instruction bytes for separate base
resolution. Wire size, object count, inflation size and expansion ratio have
independent limits. Stage all output privately until the trailer and subsequent
object/base/connectivity validation pass; this decoder alone is not a push
validator. No Git executable, filesystem, allocator or runtime API is used.

`pack::DeltaDecoder` parses inflated delta instructions across arbitrary chunks.
It checks base/result sizes, source/target ranges, instruction count, chain depth
and exact EOF. Copy events expose ranges for bounded asynchronous base reads;
insert events borrow input fragments. It owns neither the base nor the output.
Execute every event before resuming and use `ObjectDigest` to hash output chunks
with the inherited kind and declared size. A completed delta authenticates its
syntax; the host still verifies storage I/O, object identity and connectivity.

`pack::IndexHeader` retains only a version-2 index's 1032-byte header/fanout.
Its independent `IndexLookup` states request exact ranges for binary search,
CRCs and direct/64-bit offsets, without loading the complete index. Hosts can
await reads and cache larger immutable storage pages. Authenticate index bytes,
ordering and their pack relationship before using this lookup API; parsing a
header alone does not establish integrity or trustworthy absence.

`pack::EntryDecoder` resumes at a trusted pack offset using the same bounded
entry parser as pack intake. It stops after one entry, preserving following
input bytes, and reports its CRC and plain-object ID. Compare those with the
authenticated index; resolve delta instructions separately. It verifies neither
the enclosing pack checksum nor graph connectivity.

With `write`, `pack::PackComposer` assembles fetch packs from authenticated zlib
streams without inflation/recompression. It writes fresh entry headers, CRCs and
a pack checksum with a bounded wire budget and fixed state. Reference deltas
allow a host to reorder entries or move OFS deltas between packs after resolving
their base IDs. The host supplies a unique authorized selection and its delta
base closure, and awaits storage between writes. Errors invalidate partial output.

`object::LinkDecoder` streams commit parents, root trees, tag targets and tree
entries into a host-owned graph index. It retains two caller-sized tree names,
fixed header scratch and 64-bit positions; opaque messages and blobs need no
body storage. Historical recognized tree modes are preserved and flagged when
noncanonical. The host authenticates objects, checks target existence/kinds and
all duplicate tree names, and enforces reachability and ref-update policy.
Scanner completion alone is not proof of a valid repository graph.

`pack::RangeResolver` reconstructs complete objects or partial canonical ranges
through explicit metadata/read requests. It follows nested deltas using caller
`RangeFrame` slots, with independent output, representation-work, instruction,
read-size and depth limits. Storage failures can be retried before supplying a
reply. For new staged objects, request `ObjectRange::All`, hash every output
fragment and complete pack/graph validation before publication. Existing bases
must already have authenticated metadata and canonical identities.

`pack::EntryRangeDecoder` supplies representation ranges from authenticated
compressed entries using one 32 KiB window and caller read scratch. It skips the
inflated prefix, preserves pending output under backpressure, and stops at the
requested boundary. Partial completion does not validate the unread entry tail.
Hosts can await bounded source reads and cache inflated pages/ranges to avoid
repeated prefix inflation; neither API retains complete objects or an index.

`read` enables zlib inflation, pack/delta decoding and repository validation.
`write` enables snapshots, pack/zlib encoding and pack caching. Both are enabled
by default. Object IDs, borrowed objects, repositories, readers, packet lines and
HTTP request/response values are always available.

With `read`, `checkout` provides borrowed file/symlink contents, byte-name tree
lookup and bounded tag/commit-to-tree traversal over a caller-owned `ObjectSource`.
It supports both object formats and retains only IDs and offsets between source
reads, so caches may evict the previous object on every lookup. Hosts supply
hash-verified objects and implement permissions, filesystem limits and I/O.

Part of [git-zero](https://github.com/no-std-rs/git-zero).

With `write`, `pack::Encoder` and `pack::LooseEncoder` expose resumable pulls into
caller-owned output slices. They retain stored-DEFLATE framing, Adler-32 and pack
hash state without object-sized scratch. Packs accept a borrowed selection or all
objects. Hold repository metadata, bodies and selected indices stable until EOF;
a host can recreate the repository from immutable inputs between pulls. Each call
performs at most one body read. Preserve unsent output before advancing again.
Encoding matches the synchronous stored-block writers in both object formats.

`cache::selected` caches raw stored-block packs by their exact object set. It
supports independent refs and partial selections in SHA-1/SHA-256. Complete
authorization, visible-ref/reachability checks, graph selection and traversal
budgets before every call. Pass strictly ascending selected indices with
`Selection::Indices` (or `Selection::All` for all objects). ACK-only rounds and shallow-list probes skip the cache; their
control packets are generated separately.

```rust
use git_zero_core::{
    cache::selected::{self, Buffers, FixedCache, Selection},
    io::Write,
    ObjectId, Repository, Result,
};

fn serve(
    repository: &impl Repository,
    indices: &[usize],
    cache: &mut FixedCache<'_>,
    output: &mut impl Write,
) -> Result<()> {
    let mut ids = [ObjectId::Sha1([0; 20]); 64]; // One slot per selected object.
    let mut staging = [0; 8192];
    selected::write(repository, Selection::Indices(indices), cache, Buffers {
        ids: &mut ids,
        pack: &mut staging,
        read: &mut [0; 1024],
        byte_limit: 8192,
    }, output)?;
    Ok(())
}
```

Construct `FixedCache::new(&mut cache_bytes)` once from a host-owned byte buffer
and retain it across calls to `serve`, supplying a fresh response sink each time.
An unchanged authorized selection can reuse the verified pack;
`cache.statistics().hits` records successful cache hits.

Hits require ID scratch and a byte limit, with no pack staging or body reads
when the provider supplies precomputed IDs. Both hits and misses validate the
pack trailer, stored zlib framing/Adler32, canonical object hashes and exact set
before output; misses also validate before insertion. The key's 48-byte encoding
includes schema, object format, codec and encoder revision. Equivalent sets can
use different pack orders: publish pack/index URLs using the actual pack
checksum, rather than the selected-set key digest. Backend errors and
corruption propagate. Failed insertion preserves the old entry; an output error
may retain a new complete entry for retry. Hosts discard partial output and own
atomic publication, persistence and coordination between concurrent requests.