# `Linx.Netfilter.Map`
[🔗](https://github.com/oshlabs/linx/blob/v0.2.0/lib/linx/netfilter/map.ex#L1)

An nftables map — a set with associated data per element.

A map is a set where each element is `{key, value}`. The key
matches the set's `:key_type` and the value matches the map's
`:data_type`. When the `:data_type` is `:verdict`, the map is
what nft calls a **verdict map** (vmap) — rule dispatch by
lookup.

See `Linx.Netfilter.Vmap` for the verdict-map-specific constructor
helper that wraps `Map.new/2` with `data_type: :verdict`.

## Fields

Same as `Linx.Netfilter.Set`, plus:

  * `:data_type` — value-type atom. The basic atomic types or
    `:verdict`. Concatenations are not yet implemented.

## Construction

    iex> Map.new("port_to_chain", key_type: :inet_service, data_type: :verdict,
    ...>          elements: [{22, Linx.Netfilter.Verdict.jump("ssh_in")},
    ...>                     {80, Linx.Netfilter.Verdict.jump("http_in")}])
    {:ok, %Linx.Netfilter.Map{name: "port_to_chain", data_type: :verdict, ...}}

    iex> Map.new("dnat_targets", key_type: :inet_service, data_type: :ipv4_addr)
    {:ok, %Linx.Netfilter.Map{...}}

Errors: `{:error, {:bad_map, reason}}`. Element-shape errors:
`{:error, {:bad_map_element, reason}}`.

# `data_type`

```elixir
@type data_type() :: Linx.Netfilter.Set.key_type() | :verdict
```

# `t`

```elixir
@type t() :: %Linx.Netfilter.Map{
  comment: String.t() | nil,
  data_type: data_type(),
  elements: [{term(), term()}],
  flags: [Linx.Netfilter.Set.flag()],
  gc_interval: pos_integer() | nil,
  handle: pos_integer() | nil,
  key_type: Linx.Netfilter.Set.key_type(),
  name: String.t(),
  size: pos_integer() | nil,
  table: String.t() | nil,
  timeout: pos_integer() | nil
}
```

# `add_elements`

```elixir
@spec add_elements(t(), [{term(), term()}]) ::
  {:ok, t()} | {:error, {:bad_map_element, term()}}
```

Adds elements to a map, validating each `{key, value}` against
the map's `:key_type` / `:data_type`. For verdict maps, values
are accepted as `%Verdict{}` or any input form `Verdict.new!/1`
understands (and normalised to `%Verdict{}` in the result).

# `delete_elements`

```elixir
@spec delete_elements(t(), [term()]) :: {:ok, t()}
```

Removes elements from a map by key — both `{key, value}` and
bare `key` are accepted.

# `new`

```elixir
@spec new(
  String.t(),
  keyword()
) :: {:ok, t()} | {:error, {:bad_map, term()}}
```

Builds a map.

# `new!`

```elixir
@spec new!(
  String.t(),
  keyword()
) :: t()
```

Bang variant of `new/2`.

---

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