# `Raxol.Core.Utils.Validation`
[🔗](https://github.com/DROOdotFOO/raxol/blob/v2.8.0/lib/raxol/core/utils/validation.ex#L1)

Common validation utilities to reduce code duplication across the codebase.
Provides standardized validation functions for dimensions, configs, and common patterns.

# `terminal_size_ceiling`

```elixir
@type terminal_size_ceiling() :: %{
  width: pos_integer(),
  height: pos_integer(),
  cells: pos_integer()
}
```

A terminal size ceiling: largest width, height and width * height.

# `clamp_terminal_size`

```elixir
@spec clamp_terminal_size(term(), term(), terminal_size_ceiling()) :: {term(), term()}
```

Clamps a terminal size to a ceiling, by default the local one,
`Raxol.Core.Defaults.terminal_size_ceiling/0`. Network surfaces pass
`Raxol.Core.Defaults.remote_terminal_size_ceiling/0` (or their own).

The width is capped at the ceiling's `:width`, then the height at its
`:height` and at as many rows as its `:cells` allows at that width, so
`width * height` never exceeds the cell ceiling. Only the upper bound is
applied: a size already within the ceiling, and a non-positive or
non-integer value, comes back unchanged.

    iex> Raxol.Core.Utils.Validation.clamp_terminal_size(120, 40)
    {120, 40}

    iex> Raxol.Core.Utils.Validation.clamp_terminal_size(100_000, 100_000)
    {4096, 256}

    iex> Raxol.Core.Utils.Validation.clamp_terminal_size(
    ...>   100_000,
    ...>   100_000,
    ...>   Raxol.Core.Defaults.remote_terminal_size_ceiling()
    ...> )
    {512, 256}

# `validate_bounds`

```elixir
@spec validate_bounds(number(), number(), number()) ::
  {:ok, number()} | {:error, :out_of_bounds}
```

Validates that a value is within specified bounds.

# `validate_config`

```elixir
@spec validate_config(map(), [atom()]) ::
  {:ok, map()} | {:error, {:missing_keys, [atom()]}}
```

Validates a configuration map against required keys.

# `validate_coordinates`

```elixir
@spec validate_coordinates(integer(), integer()) ::
  {:ok, {non_neg_integer(), non_neg_integer()}} | {:error, :invalid_coordinates}
```

Validates that coordinates are valid non-negative integers.

# `validate_dimension`

```elixir
@spec validate_dimension(integer(), non_neg_integer()) :: non_neg_integer()
```

Validates that a dimension is a positive integer, returning default if invalid.

It sets no upper bound; a terminal width or height goes through
`clamp_terminal_size/2` or `validate_terminal_size/2` as well.

# `validate_enum`

```elixir
@spec validate_enum(any(), list()) :: {:ok, any()} | {:error, :invalid_option}
```

Validates that a value is one of the allowed options.

# `validate_list_types`

```elixir
@spec validate_list_types(list(), atom()) :: {:ok, list()} | {:error, :invalid_types}
```

Validates that a list contains only specific types.

# `validate_string`

```elixir
@spec validate_string(binary(), Regex.t() | nil) ::
  {:ok, binary()} | {:error, :invalid_string}
```

Validates that a string is not empty and optionally matches a pattern.

# `validate_terminal_size`

```elixir
@spec validate_terminal_size(term(), term(), terminal_size_ceiling()) ::
  :ok | {:error, :invalid_dimensions | :dimensions_too_large}
```

Checks a terminal size against the ceiling `clamp_terminal_size/3` applies,
by default the local one.

Returns `{:error, :invalid_dimensions}` unless both are positive integers,
and `{:error, :dimensions_too_large}` when either axis, or
`width * height`, is past the ceiling.

---

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