# `Exgit.ObjectStore`
[🔗](https://github.com/ivarvong/exgit/blob/v0.1.0/lib/exgit/object_store.ex#L1)

Storage protocol for git objects, keyed by binary SHA-1.

Implemented by `Exgit.ObjectStore.Memory` (in-heap),
`Exgit.ObjectStore.Disk` (git's on-disk layout), and
`Exgit.ObjectStore.Promisor` (lazy, fetch-on-demand).

Stores are pure values: every write (`put/2`, `import_objects/2`,
`close_write/2`) returns the updated store, which the caller must
thread forward. Reads never mutate.

# `t`

```elixir
@type t() :: term()
```

All the types that implement this protocol.

# `cancel_write`

```elixir
@spec cancel_write(t(), term()) :: :ok
```

Abort the write session and release any associated resources (open ports,
temp files, etc.) without persisting the object. Always returns `:ok`.

# `close_write`

```elixir
@spec close_write(t(), term()) :: {:ok, binary(), t()} | {:error, term()}
```

Finalise the write session: compute the object SHA, persist the object,
and return the updated store. Returns `{:ok, sha, updated_store}`.

# `get`

```elixir
@spec get(t(), binary()) :: {:ok, Exgit.Object.t()} | {:error, term()}
```

# `has?`

```elixir
@spec has?(t(), binary()) :: boolean()
```

# `import_objects`

```elixir
@spec import_objects(t(), [{atom(), binary(), binary()}]) :: {:ok, t()}
```

# `object_size`

```elixir
@spec object_size(t(), binary()) ::
  {:ok, non_neg_integer()} | {:error, :not_found | :not_local | term()}
```

Uncompressed byte size of an object WITHOUT materializing its content.

The point is a constant-memory size check: callers can decide whether a
blob is too large to read before paying to inflate it into the heap.

Returns `{:ok, byte_count}` when the store can answer, or:

  * `{:error, :not_found}` — the object is genuinely absent from the
    store.
  * `{:error, :not_local}` — a meaningful, non-fatal result for lazy
    stores (`Promisor`): it means "knowing this size requires a network
    fetch", so the caller can opt in rather than have a multi-GB fetch
    triggered behind a size check.
  * `{:error, term()}` — store-specific failure (e.g. a corrupt loose
    object on disk).

# `open_write`

```elixir
@spec open_write(t(), Exgit.Object.object_type(), non_neg_integer()) ::
  {:ok, term()} | {:error, term()}
```

Open a streaming write session for an object of `type` and `expected_size`
bytes (the declared uncompressed size from the pack header).

Returns `{:ok, handle}` where handle is an opaque term, or
`{:error, :not_supported}` for stores that do not implement the streaming API.

# `put`

```elixir
@spec put(t(), Exgit.Object.t()) :: {:ok, binary(), t()}
```

# `write_chunk`

```elixir
@spec write_chunk(t(), term(), binary()) :: {:ok, term()} | {:error, term()}
```

Append a chunk of uncompressed content to the in-progress write session.
Returns `{:ok, updated_handle}`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
