# `VFS.Memory`
[🔗](https://github.com/ivarvong/vfs/blob/v0.1.0/lib/vfs/memory.ex#L1)

In-memory `VFS.Mountable` backend.

Files live in a `tree` map (`%{path => binary}`); explicitly-created
empty directories live in a `dirs` `MapSet`; `mtimes` tracks
modification times.

Directories are recognized in two ways:

  1. **Explicit** — created via `mkdir/3`, recorded in `dirs`.
  2. **Implicit** — at least one file or explicit dir under them.

Both kinds satisfy `stat/2` and `readdir/2`. Removing the last child of an
implicit directory makes it disappear; an explicit directory persists
until removed via `rm/3` with `recursive: true`.

## Construction

    iex> mem = VFS.Memory.new(%{"/foo/bar" => "hello"})
    iex> {:ok, "hello", _mem} = VFS.read_file(mem, "/foo/bar")
    iex> :ok
    :ok

Use the helpers in `VFS` (e.g. `VFS.read_file/2`, `VFS.walk/3`) for
telemetry-instrumented access. Direct protocol calls bypass instrumentation.

# `t`

```elixir
@type t() :: %VFS.Memory{
  dirs: MapSet.t(VFS.Path.t()),
  mtimes: %{required(VFS.Path.t()) =&gt; DateTime.t()},
  tree: %{required(VFS.Path.t()) =&gt; binary()}
}
```

# `new`

```elixir
@spec new(%{optional(String.t()) =&gt; binary()}) :: t()
```

Build a fresh in-memory FS, optionally seeded with files.

Raises `ArgumentError` if the seed is malformed:

  * Every key must be a path binary and every value a binary —
    anything else fails here, at construction, instead of deferring
    the crash to the first `stat`/`read`.
  * The literal `"/"` cannot be a file (root is always a directory).
  * No two paths can be in a strict path-segment-prefix relationship
    (e.g. `%{"/a" => "...", "/a/b" => "..."}` is rejected — `/a`
    cannot simultaneously be a regular file and a directory).

Validation runs at construction so the resulting backend is internally
consistent: `stat`, `readdir`, and `read_file` agree on every path.
Without validation, externally-provided seeds (config files, DB dumps,
LLM-generated inputs) could put the FS into a state that no sequence
of writes could ever produce.

## Examples

    iex> mem = VFS.Memory.new()
    iex> mem.tree
    %{}

    iex> mem = VFS.Memory.new(%{"/a.txt" => "hi"})
    iex> Map.fetch!(mem.tree, "/a.txt")
    "hi"

    iex> VFS.Memory.new(%{"/a" => "f", "/a/b" => "c"})
    ** (ArgumentError) VFS.Memory seed has conflicting paths: "/a" is a file but "/a/b" places a child under it. A path cannot be both a file and a directory.

---

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