# `ShortUUID.Core`
[🔗](https://github.com/gpedic/ex_shortuuid/blob/v4.3.0/lib/shortuuid/core.ex#L1)

Core module for ShortUUID encoding and decoding.

This module provides the core functionality for encoding and decoding UUIDs
using various alphabets. It includes functions for parsing UUIDs, encoding
them into shorter strings, and decoding those strings back into UUIDs.

## Functions

- `parse_uuid/1` - Parses a UUID string into a normalized format.
- `encode_binary/5` - Encodes a UUID into a shorter string using the specified alphabet.
- `decode_string/4` - Decodes a shortened string back into a UUID.
- `format_uuid/1` - Formats an integer value as a UUID string.
- `encode_int/5` - Encodes an integer value into a string using the specified alphabet.
- `build_decode_index/1` - Builds the lookup structure used by `decode_string/4`.

Alphabet symbols are matched by their exact codepoints, not by grapheme
clusters. Symbols that visually merge when placed next to each other (for
example combining marks or regional indicators) are therefore handled
correctly, as long as no symbol is a prefix of another symbol.

# `decode_index`

```elixir
@type decode_index() ::
  {:shortuuid_decode_index, map(), pos_integer()}
  | {:shortuuid_ascii_index, tuple()}
```

Lookup structure built by `build_decode_index/1`; treat it as opaque.

# `normalized_uuid`

```elixir
@type normalized_uuid() :: String.t()
```

# `short_uuid`

```elixir
@type short_uuid() :: String.t()
```

# `uuid_string`

```elixir
@type uuid_string() :: String.t()
```

# `build_decode_index`

```elixir
@spec build_decode_index([String.t()]) :: decode_index()
```

Builds the decode index for a list of alphabet symbols, where the position of a
symbol in the list is its digit value.

No symbol may be a prefix of another symbol (compared by codepoints), otherwise
an `ArgumentError` is raised.

If every symbol is a single ASCII character, the index is a byte lookup table,
which decodes faster. Input is then rejected as soon as a byte is not one of the
symbols; every byte of a non-ASCII character is 128 or higher, so it can never
match.

# `decode_string`

```elixir
@spec decode_string(String.t(), pos_integer(), decode_index() | map(), pos_integer()) ::
  {:ok, uuid_string()} | {:error, String.t()}
```

Decodes a shortened string back into a UUID using the specified base and alphabet.
Validates the input length and ensures the decoded value is within valid UUID range.

The index should be built with `build_decode_index/1`. A plain map of
`symbol => value` is also accepted, but is converted on every call.

## Examples

    iex> alphabet = String.graphemes("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") |> Enum.with_index() |> Map.new()
    iex> ShortUUID.Core.decode_string("BWBeN28Vb7cMEx7Ym8AUzs", 58, alphabet, 22)
    {:ok, "550e8400-e29b-41d4-a716-446655440000"}

    iex> alphabet = String.graphemes("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") |> Enum.with_index() |> Map.new()
    iex> ShortUUID.Core.decode_string("invalid", 58, alphabet, 22)
    {:error, "Invalid input"}

# `encode_binary`

```elixir
@spec encode_binary(uuid_string(), pos_integer(), tuple(), pos_integer(), String.t()) ::
  {:ok, short_uuid()} | {:error, String.t()}
```

Encodes a UUID string into a shorter string using the specified alphabet and base.
Takes a UUID string, base number, alphabet tuple, desired length, and padding character.

## Examples

    iex> alphabet = String.graphemes("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") |> List.to_tuple()
    iex> ShortUUID.Core.encode_binary("550e8400-e29b-41d4-a716-446655440000", 58, alphabet, 22, "1")
    {:ok, "BWBeN28Vb7cMEx7Ym8AUzs"}

    iex> alphabet = String.graphemes("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") |> List.to_tuple()
    iex> ShortUUID.Core.encode_binary("invalid", 58, alphabet, 22, "1")
    {:error, "Invalid UUID"}

# `encode_int`

```elixir
@spec encode_int(binary(), pos_integer(), tuple(), pos_integer(), String.t()) ::
  {:ok, short_uuid()} | {:error, String.t()}
```

Encodes a 128-bit integer into a string using the specified base and alphabet.
Pads the result to the desired length using the padding character.

Returns `{:error, "Invalid UUID"}` if the input is not a 16-byte binary.

# `format_uuid`

```elixir
@spec format_uuid(0..340_282_366_920_938_463_463_374_607_431_768_211_455) ::
  uuid_string()
```

Formats a 128-bit integer as a standard UUID string with dashes.
Converts the integer to a 32-character hex string and inserts dashes in the correct positions.
Raises a `FunctionClauseError` if the value is negative or does not fit in 128 bits.

## Examples

    iex> ShortUUID.Core.format_uuid(0x550e8400e29b41d4a716446655440000)
    "550e8400-e29b-41d4-a716-446655440000"

# `parse_uuid`

```elixir
@spec parse_uuid(String.t()) :: {:ok, normalized_uuid()} | {:error, String.t()}
```

Parses the supported UUID string formats (with or without hyphens, in curly
braces or with a `urn:uuid:` prefix) into 32 hex digits without separators.
The letter case of the hex digits is preserved.

## Examples

    iex> ShortUUID.Core.parse_uuid("550e8400-e29b-41d4-a716-446655440000")
    {:ok, "550e8400e29b41d4a716446655440000"}

    iex> ShortUUID.Core.parse_uuid("{550e8400-e29b-41d4-a716-446655440000}")
    {:ok, "550e8400e29b41d4a716446655440000"}

    iex> ShortUUID.Core.parse_uuid("urn:uuid:550e8400-e29b-41d4-a716-446655440000")
    {:ok, "550e8400e29b41d4a716446655440000"}

    iex> ShortUUID.Core.parse_uuid("not-a-uuid")
    {:error, "Invalid UUID"}

---

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