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 bydecode_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.
Summary
Types
Lookup structure built by build_decode_index/1; treat it as opaque.
Functions
Builds the decode index for a list of alphabet symbols, where the position of a symbol in the list is its digit value.
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.
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.
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.
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.
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.
Types
@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.
@type normalized_uuid() :: String.t()
@type short_uuid() :: String.t()
@type uuid_string() :: String.t()
Functions
@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.
@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"}
@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"}
@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.
@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"
@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"}