# `Estructura.WIA`
[🔗](https://github.com/am-kantox/estructura/blob/v1.15.0/lib/estructura/wia.ex#L1)

`Estructura.WIA` (With Indifferent Access) provides a struct-like container
  that can be accessed by both atom and binary keys, replicating
  Ruby's `Hash#with_indifferent_access` pattern.

Internally, keys are always stored as atoms. Both atom and binary keys
  are accepted in `Access` operations and normalized to atoms transparently.

This module builds on top of `Estructura`, reusing its `Access` implementation,
  coercion, validation, and `Enumerable` protocol. It adds indifferent key
  normalization, and implements `Inspect`, `Collectable`, and optionally
  `Jason.Encoder` protocols to mimic map behaviour.

## Usage

```elixir
defmodule MyWIA do
  use Estructura.WIA,
    fields: [
      foo: [default: 42],
      bar: [default: ""],
      baz: [default: %{}]
    ]

  @impl MyWIA.Coercible
  def coerce_foo(value) when is_integer(value), do: {:ok, value}
  def coerce_foo(value) when is_binary(value) do
    case Integer.parse(value) do
      {int, ""} -> {:ok, int}
      _ -> {:error, "not a valid integer"}
    end
  end

  @impl MyWIA.Validatable
  def validate_foo(value) when value >= 0, do: {:ok, value}
  def validate_foo(_), do: {:error, ":foo must be non-negative"}
end
```

Then both atom and binary keys work interchangeably:

```elixir
wia = %MyWIA{}
wia[:foo]        #=> 42
wia["foo"]       #=> 42
put_in(wia, ["foo"], 100)  #=> %MyWIA{foo: 100, ...}
```

## Options

* `fields` — a keyword list of `{field_name, opts}` where `opts` is a keyword list with:
  * `:default` — the default value for the field (default: `nil`)
  * `:coerce` — whether to generate a coercion callback for this field (default: `false`)
  * `:validate` — whether to generate a validation callback for this field (default: `false`)

## Protocols

`Inspect`, `Enumerable`, and `Collectable` protocols are automatically
  implemented to mimic plain map behaviour.
If `Jason` is compiled and available, `Jason.Encoder` is also derived.

---

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