defmodule SC.Event do @moduledoc """ Represents an event that can be sent to a state chart. Events can be external (from outside the state chart) or internal (generated by the state chart itself, e.g., from actions). """ defstruct [:name, data: %{}, origin: :external] @type origin :: :external | :internal @type t :: %__MODULE__{ name: String.t(), data: map(), origin: origin() } @doc """ Create a new external event. """ @spec new(String.t(), map()) :: t() def new(name, data \\ %{}) when is_binary(name) and is_map(data) do %__MODULE__{name: name, data: data, origin: :external} end @doc """ Create a new internal event. """ @spec internal(String.t(), map()) :: t() def internal(name, data \\ %{}) when is_binary(name) and is_map(data) do %__MODULE__{name: name, data: data, origin: :internal} end @doc """ Check if an event is external. """ @spec external?(t()) :: boolean() def external?(%__MODULE__{origin: :external}), do: true def external?(%__MODULE__{}), do: false @doc """ Check if an event is internal. """ @spec internal?(t()) :: boolean() def internal?(%__MODULE__{origin: :internal}), do: true def internal?(%__MODULE__{}), do: false @doc """ Check if this event matches a transition's event specification. For now, only supports exact string matching. """ @spec matches?(t(), String.t() | nil) :: boolean() def matches?(%__MODULE__{}, nil), do: false def matches?(%__MODULE__{name: name}, event_spec) when is_binary(event_spec) do name == event_spec end end