View Source Uniq.UUID (Uniq v0.6.1)

This module provides RFC 4122 compliant universally unique identifiers (UUIDs).

See the README for general usage information.

Link to this section Summary

Functions

Compares two UUIDs, using their canonical 128-bit integer form, as described in RFC 4122.

This function parses the given UUID, in any of the supported encodings/formats, and produces the information gleaned from the encoded data.

Like info/1, but raises if the input UUID is invalid.

Parses a Elixir.Uniq.UUID from a binary.

This function takes a UUID string in any of the formats supported by to_string/1, and returns the raw, binary-encoded form.

Formats a Elixir.Uniq.UUID as a string, using the format it was originally generated with.

Same as to_string/1, except you can specify the desired format.

Generates a UUID using the version 1 scheme, as described in RFC 4122

This function is the same as uuid/1, except the caller provides the clock sequence value and the node identifier (which must be a 6-byte binary).

Generates a UUID using the version 3 scheme, as described in RFC 4122

Generates a UUID using the version 4 scheme, as described in RFC 4122

Generates a UUID using the version 5 scheme, as described in RFC 4122

Generates a UUID using the proposed version 6 scheme, found here. This is a draft extension of RFC 4122, but has not yet been formally accepted.

Generates a UUID using the proposed version 7 scheme, found here. This is a draft extension of RFC 4122, but has not yet been formally accepted.

Returns true if the given string is a valid UUID.

Link to this section Types

@type format() :: :default | :raw | :hex | :urn | :slug
@type formatted() :: t() | <<_::360>> | <<_::288>> | <<_::256>> | <<_::176>>
@type info() :: %Uniq.UUID{
  bytes: t(),
  format: :raw | :hex | :default | :urn | :slug,
  node: <<_::48>>,
  seq: non_neg_integer(),
  time: non_neg_integer(),
  variant: bitstring(),
  version: 1..8
}
@type namespace() :: :dns | :url | :oid | :x500 | nil | formatted()
@type t() :: <<_::128>>

Link to this section Functions

@spec compare(String.t() | info(), String.t() | info()) :: :lt | :eq | :gt

Compares two UUIDs, using their canonical 128-bit integer form, as described in RFC 4122.

You may provide the UUIDs in either string, binary, or as a Uniq.UUID struct.

See :binary.decode_hex/1.

See :binary.encode_hex/1.

Link to this function

info(bin, style \\ :struct)

View Source
@spec info(binary(), :struct) :: {:ok, info()} | {:error, term()}
@spec info(binary(), :keyword) :: {:ok, Keyword.t()} | {:error, term()}

This function parses the given UUID, in any of the supported encodings/formats, and produces the information gleaned from the encoded data.

Two styles of information are supported, depending on whether the function is called via the compatibility shim for :elixir_uuid, or directly. You may pass :struct or :keyword manually if you wish to express a preference for one style or the other.

The :struct form is the UUID structure used internally by this library, and it contains all of the information needed to re-encode the UUID as binary.

The :keyword form matches 1:1 the keyword list produced by UUID.info/1 provided by the :elixir_uuid library, and it contains slightly less information, but is useful for compatibility with legacy code that operates on that structure.

Examples

iex> Uniq.UUID.info("870df8e8-3107-4487-8316-81e089b8c2cf", :keyword)
{:ok, [uuid: "870df8e8-3107-4487-8316-81e089b8c2cf",
 binary: <<135, 13, 248, 232, 49, 7, 68, 135, 131, 22, 129, 224, 137, 184, 194, 207>>,
 type: :default,
 version: 4,
 variant: :rfc4122]}

iex> Uniq.UUID.info("870df8e8-3107-4487-8316-81e089b8c2cf")
{:ok, %Uniq.UUID{
 format: :default,
 version: 4,
 variant: <<2::2>>,
 time: 326283406408022248,
 seq: 790,
 node: <<129, 224, 137, 184, 194, 207>>,
 bytes: <<135, 13, 248, 232, 49, 7, 68, 135, 131, 22, 129, 224, 137, 184, 194, 207>>,
}}
Link to this function

info!(bin, style \\ :struct)

View Source
@spec info!(binary(), :struct) :: info() | no_return()
@spec info!(binary(), :keyword) :: Keyword.t() | no_return()

Like info/1, but raises if the input UUID is invalid.

@spec parse(binary()) :: {:ok, info()} | {:error, term()}

Parses a Elixir.Uniq.UUID from a binary.

Supported formats include human-readable strings, as well as the raw binary form of the UUID.

examples

Examples

iex> {:ok, uuid} = Uniq.UUID.parse("f81d4fae-7dec-11d0-a765-00a0c91e6bf6")
{:ok, %Uniq.UUID{
  bytes: <<248, 29, 79, 174, 125, 236, 17, 208, 167, 101, 0, 160, 201, 30, 107, 246>>,
  format: :default,
  node: <<0, 160, 201, 30, 107, 246>>,
  seq: 10085,
  time: 130742845922168750,
  variant: <<2::size(2)>>,
  version: 1
}}
...> {:ok, %Uniq.UUID{uuid | format: :urn}} == Uniq.UUID.parse("urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6")
true

iex> match?({:ok, %Uniq.UUID{format: :default, version: 1}}, Uniq.UUID.uuid1() |> Uniq.UUID.parse())
true
@spec string_to_binary!(String.t()) :: t() | no_return()

This function takes a UUID string in any of the formats supported by to_string/1, and returns the raw, binary-encoded form.

@spec to_string(formatted() | info()) :: String.t()

Formats a Elixir.Uniq.UUID as a string, using the format it was originally generated with.

See to_string/2 if you want to specify what format to produce.

@spec to_string(formatted() | info(), format()) :: String.t()

Same as to_string/1, except you can specify the desired format.

The format can be one of the following:

  • :default, produces strings like "f81d4fae-7dec-11d0-a765-00a0c91e6bf6"
  • :urn, produces strings like "urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6"
  • :hex, produces strings like "f81d4fae7dec11d0a76500a0c91e6bf6"
  • :slug, produces strings like "-B1Prn3sEdCnZQCgyR5r9g=="
  • :raw, produces the raw binary encoding of the uuid in 128 bits
Link to this function

uuid1(format \\ :default)

View Source
@spec uuid1(format()) :: t()

Generates a UUID using the version 1 scheme, as described in RFC 4122

This scheme is based on a few key properties:

  • A timestamp, based on the count of 100-nanosecond intervals since the start of the Gregorian calendar, i.e. October 15th, 1582, in Coordinated Universal Time (UTC).
  • A clock sequence number, used to ensure that UUIDs generated with the same timestamp are still unique, by incrementing the sequence each time a UUID is generated with the same timestamp as the last UUID that was generated. This sequence is initialized with random bytes at startup, to protect against conflicts.
  • A node identifier, which is based on the MAC address of one of the network interfaces on the system, or if unavailable, using random bytes. In our case, we specifically look for the first network interface returned by :inet.getifaddrs/0 that is up, broadcastable, and has a hardware address, otherwise falling back to cryptographically strong random bytes.
Link to this function

uuid1(clock_seq, arg, format \\ :default)

View Source
@spec uuid1(clock_seq :: non_neg_integer(), node :: <<_::48>>, format()) :: t()

This function is the same as uuid/1, except the caller provides the clock sequence value and the node identifier (which must be a 6-byte binary).

See uuid/1 for details.

Link to this function

uuid3(namespace, name, format \\ :default)

View Source
@spec uuid3(namespace(), name :: binary(), format()) :: t()

Generates a UUID using the version 3 scheme, as described in RFC 4122

This scheme provides the means for generating UUIDs deterministically, given a namespace and a name. This means that with the same inputs, you get the same UUID as output.

The main difference between this and the version 5 scheme, is that version 3 uses MD5 for hashing, and version 5 uses SHA1. Both hashes are deprecated these days, but you should prefer version 5 unless otherwise required.

In this scheme, the timestamp, clock sequence and node value are constructed from the namespace and name, as described in RFC 4122, Section 4.3.

namespaces

Namespaces

You may choose one of several options for namespacing your UUIDs:

  1. Use a predefined namespace. These are provided by RFC 4122 in order to provide namespacing for common types of names. See below.
  2. Use your own namespace. For this, simply generate a UUID to represent the namespace. You may provide this UUID in whatever format is supported by parse/1.
  3. Use nil. This is bound to a special-case UUID that has no intrinsic meaning, but is valid for use as a namespace.

The set of predefined namespaces consist of the following:

  • :dns, intended for namespacing fully-qualified domain names
  • :url, intended for namespacing URLs
  • :oid, intended for namespacing ISO OIDs
  • :x500, intended for namespacing X.500 DNs (in DER or text output format)

notes

Notes

One thing to be aware of with version 3 and 5 UUIDs, is that unlike version 1 and 6, the lexicographical ordering of UUIDs of generated one after the other, is entirely random, as the most significant bits are dependent upon the hash of the namespace and name, and thus not based on time or even the lexicographical ordering of the name.

This is generally worth the tradeoff in favor of determinism, but it is something to be aware of.

Likewise, since the generation is deterministic, care must be taken to ensure that you do not try to use the same name for two different objects within the same namespace. This should be obvious, but since the other schemes are not sensitive in this way, it is worth calling out.

Link to this function

uuid4(format \\ :default)

View Source
@spec uuid4(format()) :: t()

Generates a UUID using the version 4 scheme, as described in RFC 4122

This scheme is like the version 1 scheme, except it uses randomly generated data for the timestamp, clock sequence, and node fields.

This scheme is the closest you can get to truly unique identifiers, as they are based on truly random (or pseudo-random) data, so the chances of generating the same UUID twice is astronomically small.

notes

Notes

The version 4 scheme does have some deficiencies. Namely, since they are based on random data, the lexicographical ordering of the resulting UUID is itself random, which can play havoc with database indices should you choose to use UUIDs for primary keys.

It is strongly recommended to consider the version 6 scheme instead. They are almost the same as a version 1 UUID, but with improved semantics that combine some of the beneficial traits of version 4 UUIDs without the lexicographical ordering downsides. The only caveat to that recommendation is if you need to pass them through a system that inspects the UUID encoding itself and doesn't have preliminary support for version 6.

Link to this function

uuid5(namespace, name, format \\ :default)

View Source
@spec uuid5(namespace(), name :: binary(), format()) :: t()

Generates a UUID using the version 5 scheme, as described in RFC 4122

This scheme provides the means for generating UUIDs deterministically, given a namespace and a name. This means that with the same inputs, you get the same UUID as output.

The main difference between this and the version 5 scheme, is that version 3 uses MD5 for hashing, and version 5 uses SHA1. Both hashes are deprecated these days, but you should prefer version 5 unless otherwise required.

In this scheme, the timestamp, clock sequence and node value are constructed from the namespace and name, as described in RFC 4122, Section 4.3.

namespaces

Namespaces

You may choose one of several options for namespacing your UUIDs:

  1. Use a predefined namespace. These are provided by RFC 4122 in order to provide namespacing for common types of names. See below.
  2. Use your own namespace. For this, simply generate a UUID to represent the namespace. You may provide this UUID in whatever format is supported by parse/1.
  3. Use nil. This is bound to a special-case UUID that has no intrinsic meaning, but is valid for use as a namespace.

The set of predefined namespaces consist of the following:

  • :dns, intended for namespacing fully-qualified domain names
  • :url, intended for namespacing URLs
  • :oid, intended for namespacing ISO OIDs
  • :x500, intended for namespacing X.500 DNs (in DER or text output format)

notes

Notes

One thing to be aware of with version 3 and 5 UUIDs, is that unlike version 1 and 6, the lexicographical ordering of UUIDs of generated one after the other, is entirely random, as the most significant bits are dependent upon the hash of the namespace and name, and thus not based on time or even the lexicographical ordering of the name.

This is generally worth the tradeoff in favor of determinism, but it is something to be aware of.

Likewise, since the generation is deterministic, care must be taken to ensure that you do not try to use the same name for two different objects within the same namespace. This should be obvious, but since the other schemes are not sensitive in this way, it is worth calling out.

Link to this function

uuid6(format \\ :default)

View Source
@spec uuid6(format()) :: t()

Generates a UUID using the proposed version 6 scheme, found here. This is a draft extension of RFC 4122, but has not yet been formally accepted.

Version 6 provides the following benefits over versions 1 and 4:

  • Like version 1, it is time-based, but unlike version 1, it is naturally sortable by time in its raw binary encoded form
  • Like version 4, it provides better guarantees of uniqueness and privacy, by basing itself on random or pseudo-random data, rather than MAC addresses and other potentially sensitive information.
  • Unlike version 4, which tends to interact poorly with database indices due to being derived entirely from random or pseudo-random data; version 6 ensures that the most significant bits of the binary encoded form are a 1:1 match with the most significant bits of the timestamp on which it was derived. This guarantees that version 6 UUIDs are naturally sortable in the order in which they were generated (with some randomness among those which are generated at the same time).

There have been a number of similar proposals that address the same set of flaws. For example:

Systems that do not involve legacy UUIDv1 SHOULD consider using UUIDv7 instead.

Link to this function

uuid7(format \\ :default)

View Source
@spec uuid7(format()) :: t()

Generates a UUID using the proposed version 7 scheme, found here. This is a draft extension of RFC 4122, but has not yet been formally accepted.

UUID version 7 features a time-ordered value field derived from the widely implemented and well known Unix Epoch timestamp source, the number of milliseconds seconds since midnight 1 Jan 1970 UTC, leap seconds excluded. As well as improved entropy characteristics over versions 1 or 6.

Implementations SHOULD utilize UUID version 7 over UUID version 1 and 6 if possible.

@spec valid?(binary(), Keyword.t()) :: boolean()

Returns true if the given string is a valid UUID.

options

Options

  • strict: boolean, if true, requires strict RFC 4122 conformance, i.e. version 6 is considered invalid