lib/membrane/child.ex

defmodule Membrane.Child do
  @moduledoc """
  Module that keeps track of types used by both elements and bins
  """
  import Membrane.Element, only: [is_element_name?: 1]
  import Membrane.Bin, only: [is_bin_name?: 1]

  alias Membrane.{Bin, Element}
  @default_ref_options [group: [default: nil]]

  @type name :: Element.name() | Bin.name()
  @type group() :: any()
  @type ref :: {Membrane.Child, group(), name()} | name()

  @type options :: Element.options() | Bin.options()

  defguard is_child_name?(arg) when is_element_name?(arg) or is_bin_name?(arg)

  @type child_ref_options :: [group: group()]

  @doc """
  Returns a reference to a child.
  """
  @spec ref(name(), child_ref_options()) :: ref()
  def ref(name, options \\ []) do
    validate_name!(name)
    {:ok, options} = Bunch.Config.parse(options, @default_ref_options)
    validate_name!(options.group)

    if options.group != nil,
      do: {Membrane.Child, options.group, name},
      else: name
  end

  defp validate_name!(name) do
    if is_tuple(name) and elem(name, 0) == Membrane.Child do
      raise "Improper name: #{inspect(name)}. The name cannot match the reserved internal Membrane's pattern."
    end

    :ok
  end
end